英文:
How to do authentication on Spring Boot without using Spring Security?
问题
问题是:我需要实现一种身份验证机制,而不使用Spring Security。 技术栈:Spring Boot + React。 我首先尝试在控制器中注册会话ID并使用HashMap将会话ID绑定到用户名。 当用户注册时,会记录他们的会话ID并绑定到他们的用户名。 如果用户退出,那么会话将从映射中删除。
进一步,我唯一想到的解决方案是使用JavaScript询问服务器,以确定HashMap中是否缺少会话ID。 这种方法结果不起作用。
需要实现以下功能:如果用户在浏览器的第二个标签中进入此站点,然后如果他在第一个标签中登录,他将自动登录到第二个标签。 此外,如果用户在第一个标签上注销,第二个标签应该自动注销。
我该如何做到这一点?
我的控制器:
package com.cleanyco.weblab4backend.controller;
import com.cleanyco.weblab4backend.model.User;
import com.cleanyco.weblab4backend.repository.UserRepository;
import com.cleanyco.weblab4backend.util.MD5PasswordEncoder;
import com.google.gson.Gson;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
@RestController
public class UserController {
private static final Logger logger = Logger.getLogger(UserController.class.getName());
private final UserRepository userRepository;
public UserController(@Autowired UserRepository userRepository) {
this.userRepository = userRepository;
}
private final Map<String, String> activeSessions = new HashMap<>();
public String identificateSession(String sessionID) {
for (Map.Entry<String, String> userSession : activeSessions.entrySet()) {
if (userSession.getKey().equals(sessionID)) {
return userSession.getValue();
}
}
return null;
}
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@PostMapping("/signup")
public ResponseEntity<?> signup(HttpSession session, @RequestBody User user) {
User existingUser = userRepository.findUserByUsername(user.getUsername());
if (existingUser == null) {
logger.info("User wasn't found. Registering a new one...");
activeSessions.put(session.getId(), user.getUsername());
logger.info("Registered an active session. User: " + user.getUsername() + "; SessionID: " + session.getId());
user.setPassword(MD5PasswordEncoder.hash(user.getPassword()));
userRepository.save(user);
logger.info("User was successfully saved");
return new ResponseEntity<>(HttpStatus.OK);
} else {
logger.info("User with the same name already exists");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@PostMapping("/login")
public ResponseEntity<?> login(HttpSession session, @RequestBody User user) {
User existingUser = userRepository.findUserByUsername(user.username);
if (existingUser != null) {
String userPassword = user.getPassword();
String hashedPassword = MD5PasswordEncoder.hash(userPassword);
if (existingUser.getPassword().equals(hashedPassword)) {
logger.info("User successfully logged in");
String activeUser = identificateSession(session.getId());
if (activeUser == null) {
activeSessions.put(session.getId(), user.getUsername());
}
return new ResponseEntity<>(HttpStatus.OK);
} else {
logger.info("Invalid password was provided");
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
} else {
logger.info("User not found");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
private static final Gson gson = new Gson();
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@GetMapping(value = "/checksession", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> getActiveSession(HttpSession session) {
if (identificateSession(session.getId()) != null) {
String username = identificateSession(session.getId());
User user = userRepository.findUserByUsername(username);
return ResponseEntity.ok(gson.toJson(user));
} else {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@GetMapping("/logout")
public ResponseEntity<?> logout(HttpSession session) {
String exitUser = identificateSession(session.getId());
if (activeSessions.remove(exitUser) == null) {
logger.info("An error occurred while logging out the user: user already logged out");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} else {
activeSessions.remove(session.getId());
logger.info("User was successfully logged out. User: " + exitUser + "; SessionID: " + session.getId());
return new ResponseEntity<>(HttpStatus.OK);
}
}
}
英文:
The problem is: I need to implement an authentication mechanism without using Spring Security. Stack: Spring Boot + React. I first tried to register the session ID in the controller and bind the session ID to the username using a HashMap. When a user registers, their session ID is recorded and tied to their username. And if the user exited, then the session was deleted from the map.
Further, the only solution I came up with was asking server using JavaScript if the session ID was missing from the HashMap. The approach turned out to be inoperative.**
It is necessary to achieve the following: if the user enters this site in the second tab of the browser, then if he logged in in the first tab, he would automatically log in to the second one. Moreover, if the user logs out on the first tab, then the second one should be logged out automatically.
How can I do that?
My Controller:
import com.cleanyco.weblab4backend.model.User;
import com.cleanyco.weblab4backend.repository.UserRepository;
import com.cleanyco.weblab4backend.util.MD5PasswordEncoder;
import com.google.gson.Gson;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
@RestController
public class UserController {
private static final Logger logger = Logger.getLogger(UserController.class.getName());
private final UserRepository userRepository;
public UserController(@Autowired UserRepository userRepository) {
this.userRepository = userRepository;
}
private final Map<String, String> activeSessions = new HashMap<>();
public String identificateSession(String sessionID) {
for (Map.Entry<String, String> userSession : activeSessions.entrySet()) {
if (userSession.getKey().equals(sessionID)) {
return userSession.getValue();
}
}
return null;
}
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@PostMapping("/signup")
public ResponseEntity<?> signup(HttpSession session, @RequestBody User user) {
User existingUser = userRepository.findUserByUsername(user.getUsername());
if (existingUser == null) {
logger.info("User wasn't found. Registering a new one...");
activeSessions.put(session.getId(), user.getUsername());
logger.info("Registered an active session. User: " + user.getUsername() + "; SessionID: " + session.getId());
user.setPassword(MD5PasswordEncoder.hash(user.getPassword()));
userRepository.save(user);
logger.info("User was successfully saved");
return new ResponseEntity<>(HttpStatus.OK);
} else {
logger.info("User with the same name already exists");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@PostMapping("/login")
public ResponseEntity<?> login(HttpSession session, @RequestBody User user) {
User existingUser = userRepository.findUserByUsername(user.getUsername());
if (existingUser != null) {
String userPassword = user.getPassword();
String hashedPassword = MD5PasswordEncoder.hash(userPassword);
if (existingUser.getPassword().equals(hashedPassword)) {
logger.info("User successfully logged in");
String activeUser = identificateSession(session.getId());
if (activeUser == null) {
activeSessions.put(session.getId(), user.getUsername());
}
return new ResponseEntity<>(HttpStatus.OK);
} else {
logger.info("Invalid password was provided");
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
} else {
logger.info("User not found");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
private static final Gson gson = new Gson();
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@GetMapping(value = "/checksession", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> getActiveSession(HttpSession session) {
if (identificateSession(session.getId()) != null) {
String username = identificateSession(session.getId());
User user = userRepository.findUserByUsername(username);
return ResponseEntity.ok(gson.toJson(user));
} else {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
@GetMapping("/logout")
public ResponseEntity<?> logout(HttpSession session) {
String exitUser = identificateSession(session.getId());
if (activeSessions.remove(exitUser) == null) {
logger.info("An error occurred while logging out the user: user already logged out");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} else {
activeSessions.remove(session.getId());
logger.info("User was successfully logged out. User: " + exitUser + "; SessionID: " + session.getId());
return new ResponseEntity<>(HttpStatus.OK);
}
}
}```
</details>
# 答案1
**得分**: 1
1. 用户登录时,在浏览器本地存储中设置一个标志。
2. 用户登出时,重置/清除本地存储中的标志。
3. 每次 UI 应用程序启动时,检查本地存储中的标志。如果标志已设置,假设用户已登录,否则显示登录页面。
4. 要同步用户登出,您需要实现一个方法,定期轮询本地存储的值。如果标志被重置,假设用户从另一个标签页中登出,然后在当前标签页中执行登出操作。
<details>
<summary>英文:</summary>
To handle multiple browser window with login/logout synchronization, do following.
1. When user login, set a flag in browser local storage.
2. When user logout, reset/clear the flag in local storage.
3. Every time UI application starts, check the flag in local storage. If the flag is set, assume user has logged in else show login page.
4. To synchronize user logout, you need to implement a method which will poll the local storage value frequently, If the flag is reset, assume user log out from another tab, and do logout in current tab also.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论