Java Spring引导安全OAuth2自定义异常消息

Java Spring引导安全OAuth2自定义异常消息,java,spring,rest,spring-boot,spring-security-oauth2,Java,Spring,Rest,Spring Boot,Spring Security Oauth2,在我的spring boot RESTfull项目中有一些特殊情况,而不是auth异常错误消息的标准定制。我需要一个不同的消息,这取决于用户名或密码是否错误,用户名是否不存在,或者用户是否在数据库中被停用。目前我只能获得消息“坏凭证”,我还没有找到任何解决方案,如何根据一些用户属性或特殊情况自定义消息 我目前有如下自定义身份验证提供程序: @Component public class CustomAuthenticationProvider implements AuthenticationP

在我的spring boot RESTfull项目中有一些特殊情况,而不是auth异常错误消息的标准定制。我需要一个不同的消息,这取决于用户名或密码是否错误,用户名是否不存在,或者用户是否在数据库中被停用。目前我只能获得消息
“坏凭证”
,我还没有找到任何解决方案,如何根据一些用户属性或特殊情况自定义消息

我目前有如下自定义身份验证提供程序:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication)
            throws org.springframework.security.core.AuthenticationException {


        String name = authentication.getName();
        String password = authentication.getCredentials().toString();

        UserDetails userDetails = userDetailsService.loadUserByUsername(name);


        if(passwordEncoder.matches(password, userDetails.getPassword())) {
            return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(),
                    userDetails.getAuthorities());
        }

        return null;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }


}
@Service
public class CustomUserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService{

    @Autowired
    UserService userService; //my custom user service

    @Override
    public UserDetails loadUserByUsername(String username) {
        try {
            User user = userService.getUserByUsername(username);

            if(user == null) {
                throw new UsernameNotFoundException("Username doesn't exist");
            } else if(user.isDeactivated()) {
                throw new UsernameNotFoundException("User deactivated");
            }

            List<Authority> listOfAuthorities = userService.getAllAuthoritiesFromUser(user.getUserId());
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();

            for(Authority authority : listOfAuthorities) {
                grantedAuthorities.add(new SimpleGrantedAuthority(authority.getName()));
            }

            org.springframework.security.core.userdetails.User userNew =
            new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
            return userNew;

        }
        catch(Exception ex) {
            throw new UsernameNotFoundException("Username or password not correct");
        }

    }
}

这个关于Spring安全性的通用消息有一个目的,它混淆了登录失败的实际原因

一旦您根据需要提供特定消息,例如,
用户名不存在
用户已停用
密码不正确
,等等,您就开始为恶意用户提供太多信息

更新

如果您仍然想这样做,您可以实现自己的
AuthenticationFailureHandler
,类似的功能应该可以实现:

公共类DefaultAuthenticationFailureHandler扩展了SimpleRuthenticationFailureHandler{
@凌驾
验证失败(HttpServletRequest请求、HttpServletResponse响应、,
AuthenticationException(异常)引发IOException、ServletException{
super.onAuthenticationFailure(请求、响应、异常);
if(exception.getClass().isAssignableFrom(UsernameNotFoundException.class)){
response.sendRedirect(“未找到用户”)
}else if(exception.getClass().isAssignableFrom(LockedException.class)){
response.sendRedirect(“用户锁定”)
}
}
}

谢谢你的回答。我理解为什么默认情况下没有给出实际原因,但我有客户的具体要求。当需要更具体的信息时,是否没有针对特定情况的解决方法?再次感谢。由于我的项目是RESTfulWeb服务,我确信哪里是添加自定义故障句柄的正确位置。我用
ResourceServerConfig
SecurityConfig
更新了我的问题这看起来像是您正在寻找的解决方案。我添加了自定义入口点,但没有为
/auth/token
端点调用它,该端点是用于身份验证的oauth2端点。您是否设法解决了此问题?@aswzen实际上没有。我不得不进行额外的API调用来检查细节。
@Configuration
@EnableWebSecurity
@Order(Ordered.LOWEST_PRECEDENCE)
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    CustomUserDetailsService userDetailsService;

    @Autowired
    private CustomAuthenticationProvider authProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider)  
        .userDetailsService(userDetailsService)
        .passwordEncoder(passwordEncoder());
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.addFilterBefore(new AuthenticationTokenFilter(authenticationManager()), BasicAuthenticationFilter.class);
    }

    // must be overriden and exposed as @Bean, otherwise boot's AuthenticationManagerConfiguration will take precedence
    @Bean @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{

    @Autowired
    private AuthExceptionEntryPoint myEntryPoint;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.anonymous().and().authorizeRequests().antMatchers("/**")
                .authenticated()
                .and()
                .exceptionHandling().authenticationEntryPoint(myEntryPoint).accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

}