我尝试实现spring security + jwt。我完成了登录和注销方法,配置了jwt filter,provider和Web config。因此,主要问题是我的控制器以及如何向用户返回错误消息,例如,如果用户键入了错误的密码/用户名或用户帐户被禁止等。 我有一个基于异常处理的结构,看起来很糟糕。
控制器
@PostMapping("/log-in")
public ResponseEntity logIn(@RequestBody UserDto userDto) {
log.info("[LOG-IN] user with username " + userDto.getUsername());
try {
HashMap<String, String> response = userService.logIn(userDto);
return ResponseEntity.ok(response);
} catch (UserStatusException ex) {
return ResponseEntity.badRequest().body("Account is Pending");
} catch (UsernameNotFoundException ex) {
return ResponseEntity.badRequest().body("Could not find account!");
} catch (AuthenticationException ex) {
log.error("Wrong username or password!");
return ResponseEntity.badRequest().body("Wrong username or password!");
}
}
服务
@Override
public HashMap<String, String> logIn(UserDto userDto)throws AuthenticationException, UserStatusException{
User user = findByUsername(userDto.getUsername());
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userDto.getUsername(), userDto.getPassword())); //login
checkUserStatus(user); //check if user pending or banned
user.setUserStatus(UserStatus.ACTIVE);
String token = jwtTokenProvider.createToken(user.getUsername(), user.getUserRoles());
HashMap<String, String> response = new HashMap<>();
response.put("token", token);
response.put("username", user.getUsername());
userRepository.save(user);
return response;
}
@Override
public User findByUsername(String username)throws UsernameNotFoundException {
log.info("[UserService, findByUsername]");
User user = userRepository.findByUsername(username);
if(user == null){
log.error("User not found with {} username: ", username);
throw new UsernameNotFoundException("User not found!");
}
log.info("User {} successfully loaded ",username);
return user;
}
@Override
public void checkUserStatus(User user)throws UserStatusException {
if (user.getUserStatus().equals(UserStatus.BANNED)
|| user.getUserStatus().equals(UserStatus.PENDING)) {
throw new UserStatusException("Not confirmed");
}
}
还有其他方法可以代替此结构吗?
答案 0 :(得分:4)
您应该使用ControllerAdvice(请参阅教程here)。
这是一个特殊的类
@ControllerAdvice
public class ControllerAdvice {
@ExceptionHandler(PersonNotFoundException.class)
public ResponseEntity <VndErrors > notFoundException(final PersonNotFoundException e) {
return error(e, HttpStatus.NOT_FOUND, e.getId().toString());
}
}
它将允许您将特定的返回码和响应绑定到需要处理的每个异常,并且它将自动捕获控制器返回的所有异常。这也是在同一位置处理所有异常的好方法,而不是对每个异常进行处理...
我不确定,但是我认为您甚至可以将其绑定到API的特定映射以获取更多的粒度。
希望这项帮助!玩得开心!
答案 1 :(得分:2)
您可以将休养状态直接添加到您的自定义异常类中:
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class UsernameNotFoundException extends RuntimeException {
public UsernameNotFoundException(String message) {
super(message);
}
public UsernameNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
通过这种方式,您不再需要在控制器中捕获它们并将消息和状态添加到ResponseEntity中。