Spring Boot/Spring安全性AuthenticationEntryPoint未执行

SME*_*SME 11 spring spring-security spring-boot

我有一个创建了一个包含这个方法的类JwtAuthenticationFilter:

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    Authentication authentication = null;

    if(hasJsonToken(request)) {
        JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(getJsonToken(request)); 
        authentication = getAuthenticationManager().authenticate(jwtAuthenticationToken);           
    } else {
        throw new AuthenticationCredentialsNotFoundException(AUTHENTICATION_CREDENTIALS_NOT_FOUND_MSG);
    }

    return authentication;
}
Run Code Online (Sandbox Code Playgroud)

如果未提供JWT,则抛出AuthenticationCredentialsNotFoundException.我希望这会在我的AuthenticationEntryPoint中触发begin方法 - 看起来像这样:

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException authException) throws IOException, ServletException {   
response.sendError(HttpStatus.UNAUTHORIZED.value(),HttpStatus.UNAUTHORIZED.getReasonPhrase());
}
Run Code Online (Sandbox Code Playgroud)

开始方法没有被调用.这在我的spring安全配置(或其中的一部分)中:

@Bean
public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
    return new RestAuthenticationEntryPoint();              
}

protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
        .exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint()).and()
        .csrf().disable()
        .authorizeRequests().antMatchers(AUTHORISED_SERVICE_REQUESTS_ANT_MATCHER).authenticated()
        .anyRequest().permitAll();      
}
Run Code Online (Sandbox Code Playgroud)

我不确定这里有什么错误,我希望有人指出我.谢谢

我的SecurityConfig类扩展了WebSecurityConfigurerAdapter,并使用@Configuration和@EnableWebSecurity进行了注释.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ...
}
Run Code Online (Sandbox Code Playgroud)

我正在使用弹簧靴.

所以...最终我通过创建自定义AuthenticationFailureHandler并在我的Authentication F.ilter中注册它来获得我想要的行为

jwtAuthenticationFilter.setAuthenticationFailureHandler(new JwtAuthenticationFailureHandler());
Run Code Online (Sandbox Code Playgroud)

我现在的问题是,这是正确的做法,AuthenticationEntryPoint和AuthenticationFailureHandler有什么区别?

小智 10

这是我使用 Spring Boot / JWT 实现 AuthenticationEntryPoint 和 AccessDeniedHandler 的代码。我希望它对任何人都有帮助。

认证入口点

@Component
public class AuthenticationEntryPointJwt implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException authenticationException) throws IOException {

        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        final Map<String, Object> body = new HashMap<>();
        body.put("code", HttpServletResponse.SC_UNAUTHORIZED);
        body.put("payload", "You need to login first in order to perform this action.");

        final ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(httpServletResponse.getOutputStream(), body);
    }
}
Run Code Online (Sandbox Code Playgroud)

拒绝访问处理程序

@Component
public class AccessDeniedHandlerJwt implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {

        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);

        final Map<String, Object> body = new HashMap<>();
        body.put("code", HttpServletResponse.SC_FORBIDDEN);
        body.put("payload", "You don't have required role to perform this action.");

        final ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(httpServletResponse.getOutputStream(), body);
    }
}
Run Code Online (Sandbox Code Playgroud)

Web安全配置适配器

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private Environment env;
        @Autowired
        private SecurityUserDetailsService securityUserDetailsService;
        @Autowired
        private SecurityRequestFilter securityRequestFilter;
        @Autowired
        private AuthenticationEntryPointJwt authenticationEntryPointJwt;
        @Autowired
        private AccessDeniedHandlerJwt accessDeniedHandlerJwt;
    
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(securityUserDetailsService).passwordEncoder(passwordEncoder());
        }
    
        @Bean
        public BCryptPasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
    
            if (Boolean.parseBoolean(env.getRequiredProperty("security.disable.csrf")))
                httpSecurity.csrf().disable();
    
            httpSecurity
                    .httpBasic().disable()
                    .formLogin().disable()
                    .authorizeRequests()
                    .antMatchers(env.getRequiredProperty("security.uri.white-list").split(",")).permitAll()
                    .anyRequest().authenticated().and()
                    .exceptionHandling().authenticationEntryPoint(authenticationEntryPointJwt).and()
                    .exceptionHandling().accessDeniedHandler(accessDeniedHandlerJwt).and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            httpSecurity.addFilterBefore(securityRequestFilter, UsernamePasswordAuthenticationFilter.class);
        }
    }
Run Code Online (Sandbox Code Playgroud)

你可以在我的GitHub上查看完整的代码

https://github.com/JonathanM2ndoza/Nginx-Docker-Spring-Boot/tree/master/security/src/main/java/com/jmendoza/wallet/security


Dar*_*idl 7

AuthenticationEntryPoint和之间的区别在于AuthenticationFailureHandler前者用于“告诉”未经身份验证的用户在哪里进行身份验证,例如,通过将他们重定向到登录表单。后者用于处理错误的登录尝试。

AuthenticationEntryPoint很可能没有被调用,因为你抛出了一个异常。如果用户尝试访问需要身份验证的端点并且您没有抛出任何内容,则会调用它。在不存在凭据的情况下,不需要对用户进行身份验证就足够了,您不需要抛出异常。

如果您正在创建使用 JWT 身份验证的应用程序,您可能不想将用户重定向到任何地方,因此您只需使用org.springframework.security.web.authentication.HttpStatusEntryPoint或 像您这样的入口点来返回状态代码。