Spring Security中UserDetailService自定义错误消息实现问询
解决方案
问题核心在于:OAuth2授权服务器的token请求异常处理逻辑,并不受WebSecurityConfigurerAdapter中配置的authenticationEntryPoint管控,需要针对OAuth2的异常处理链路自定义转换器。以下是具体实现步骤:
1. 自定义业务异常类
继承Spring Security的AuthenticationException,用于承载用户状态校验的具体错误信息:
public class UserStatusException extends AuthenticationException { public UserStatusException(String message) { super(message); } }
2. 在UserDetailService中添加状态校验
在loadUserByUsername方法中,加载用户后立即校验账户状态,不符合要求时抛出自定义异常:
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 从数据库加载用户 User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } // 账户状态校验 if (!user.isEnabled()) { throw new UserStatusException("账户已禁用"); } if (!user.isEmailVerified()) { throw new UserStatusException("邮箱未验证,请先完成验证"); } if (user.isAccountLocked()) { throw new UserStatusException("账户已锁定,请联系管理员"); } // 转换为Spring Security的UserDetails返回 return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), user.isEnabled(), true, // 账户未过期 true, // 凭证未过期 !user.isAccountLocked(), // 账户未锁定 AuthorityUtils.createAuthorityList(user.getRoles().stream().map(Role::getName).toArray(String[]::new)) ); }
3. 自定义OAuth2异常转换器
实现WebResponseExceptionTranslator,将自定义异常转换为带具体信息的OAuth2响应:
@Component public class CustomOauth2ExceptionTranslator implements WebResponseExceptionTranslator<OAuth2Exception> { private final DefaultWebResponseExceptionTranslator defaultTranslator = new DefaultWebResponseExceptionTranslator(); @Override public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception { ResponseEntity<OAuth2Exception> defaultResponse = defaultTranslator.translate(e); OAuth2Exception oAuth2Exception = defaultResponse.getBody(); // 处理自定义用户状态异常 if (e instanceof UserStatusException) { CustomOAuth2Exception customException = new CustomOAuth2Exception(e.getMessage()); return new ResponseEntity<>(customException, defaultResponse.getStatusCode(), defaultResponse.getHeaders()); } // 处理用户名不存在异常 if (e instanceof UsernameNotFoundException) { CustomOAuth2Exception customException = new CustomOAuth2Exception(e.getMessage()); return new ResponseEntity<>(customException, defaultResponse.getStatusCode(), defaultResponse.getHeaders()); } return defaultResponse; } // 自定义OAuth2异常类,用于返回自定义错误码和信息 private static class CustomOAuth2Exception extends OAuth2Exception { public CustomOAuth2Exception(String message) { super(message); } @Override public String getOAuth2ErrorCode() { return "user_auth_error"; // 替换默认的invalid_grant } @Override public int getHttpErrorCode() { return HttpStatus.BAD_REQUEST.value(); // 可根据业务需求修改状态码,如403 } } }
4. 在授权服务器配置中注册异常转换器
找到继承AuthorizationServerConfigurerAdapter的授权服务器配置类,将自定义异常转换器注入并配置到端点中:
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private CustomOauth2ExceptionTranslator customOauth2ExceptionTranslator; @Autowired private UserDetailsService userDetailsService; @Autowired private AuthenticationManager authenticationManager; @Autowired private TokenStore tokenStore; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .userDetailsService(userDetailsService) .authenticationManager(authenticationManager) .tokenStore(tokenStore) .exceptionTranslator(customOauth2ExceptionTranslator); // 关键:注册自定义异常转换器 } // 其他授权服务器配置(如客户端信息、token增强等)... }
效果验证
当用户状态不符合要求时,前端会收到类似如下的响应:
{ "error": "user_auth_error", "error_description": "邮箱未验证,请先完成验证" }
内容的提问来源于stack exchange,提问作者Lyle Phillips
相关产品推荐
相关产品推荐

