security中登录失败后没有走登录失败拦截器

在进行security做用户登录时,会创建一系列的拦截器和过滤器,在进行用户校验时,我这边采用的是继承UsernamePasswordAuthenticationFilter,然后重写其中的attemptAuthentication和successfulAuthentication方法,但是在校验失败后,没有走校验失败拦截器。


public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public static final String TOKEN_HEADER = "Authorization";
public static final String TOKEN_PREFIX = "Bearer ";
private  static final Integer expire = 60*60*24*8;
private AuthenticationManager authenticationManager;

public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
}
/**
 * 进行登录验证
 */
@SneakyThrows
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    TbUser user =new TbUser(request.getParameter("username"),request.getParameter("password"));
    return authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword()));
}
/**
* 登录验证成功后,回调此方法,生成token
*1、将生成的token存入到redis中
* 2、将生成的token返回给前端
*/
@Override
protected void successfulAuthentication(HttpServletRequest request,
                                        HttpServletResponse response,
                                        FilterChain chain,
                                        Authentication auth) throws IOException, ServletException {
    User user = (User) auth.getPrincipal();
    String token = JwtUtil.generateJsonWebToken(user);
    RedisTemplate redisTemplate = SpringUtils.getBean("redisTemplate");
    redisTemplate.opsForValue().set(SystemParams.API_MAPPING_REDIS_TOKEN_PRE+user.getUsername(),token,expire, TimeUnit.SECONDS);
    // 登录成功后,返回token到body里面
    Map<String, Object> resultMap = new HashMap<>();
    resultMap.put(TOKEN_HEADER, TOKEN_PREFIX + token);
    Result result = Result.success(resultMap);
    response.getWriter().write(JSONUtil.toJsonStr(result));
  }
}

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
@EnableWebSecurity   //启用security安全框架的安全校验
public class MyWebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationFailHandler authenticationFailHandler;
@Autowired(required = true)
@Qualifier("myUserDetailService")
private UserDetailsService userDetailsService;
@Autowired
private ImageValidateFilter imageValidateFilter;
//在方法中配置用户名和密码,作为用户登录的数据
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
private static final String[] URL_WHITELIST = {
        "/logout",
        "/login.html",
        "/getImage",
        "/hello1"
};

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable()
            // 登录请求url
            .formLogin()
            .loginPage("/login.html")
            .loginProcessingUrl("/login")
            .failureHandler(authenticationFailHandler)
            // 配置拦截规则
            .and()
            .authorizeRequests()
            //.antMatchers(URL_WHITELIST).permitAll()
            .anyRequest().authenticated()//除了上面的这些请求不需要认证授权,其余全部的都需要认证授权
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            // 配置自定义的过滤器
            .and()
            //自定义的认证登录过滤器,并且在认证通过后生成Token,返回到前端
            .addFilter(new JwtAuthenticationFilter(authenticationManager()))
            //token认证过滤器
            .addFilter(new TokenVerifyFiter(authenticationManager()))
            // 图形验证码过滤器
            .addFilterBefore(imageValidateFilter, UsernamePasswordAuthenticationFilter.class);
}


@Bean
public PasswordEncoder passwordEncoder(){
    //加密方式,推荐的方式new BCryptPasswordEncoder();
    return new BCryptPasswordEncoder();
}

/**
 * 1、解决放行资源被token验证过滤器拦截问题
 * 2、WebSecurity主要是配置跟web资源相关的,比如css、js、images等等,但是这个还不是本质的区别,关键的区别如下:
 * ignore是完全绕过了spring security的所有filter,相当于不走spring security,所以ignore只适合配置静态资
 * 源的过滤,不适合api的过滤,过滤api就调用不了api了
 * permitall没有绕过spring security,其中包含了登录的以及匿名的。
 */
@Override
public void configure(WebSecurity web) {
    web.ignoring().antMatchers(URL_WHITELIST);
  }
}

这是因为一个很简单的问题,那就是这里定义的过滤器是在拦截器之前执行的,因此当UsernamePasswordAuthenticationFilter在进行校验时,发现用户名或者密码输入错误时,直接结束了,所以就没有再走到拦截器哪里了。
代码改造:


@Component
public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
public static final String TOKEN_HEADER = "Authorization";
public static final String TOKEN_PREFIX = "Bearer ";
private  static final Integer expire = 60*60*24*8;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    User user = (User) authentication.getPrincipal();
    String token = JwtUtil.generateJsonWebToken(user);
    RedisTemplate redisTemplate = SpringUtils.getBean("redisTemplate");
    redisTemplate.opsForValue().set(SystemParams.API_MAPPING_REDIS_TOKEN_PRE+user.getUsername(),token,expire, TimeUnit.SECONDS);
    // 登录成功后,返回token到body里面
    Map<String, Object> resultMap = new HashMap<>();
    resultMap.put(TOKEN_HEADER, TOKEN_PREFIX + token);
    Result result = Result.success(resultMap);
    response.getWriter().write(JSONUtil.toJsonStr(result));
  }
}
-------------------------------------------
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
@EnableWebSecurity   //启用security安全框架的安全校验
public class MyWebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationFailHandler authenticationFailHandler;
@Autowired
@Qualifier("myUserDetailService")
private UserDetailsService userDetailsService;
@Autowired
private JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler;
@Autowired
private ImageValidateFilter imageValidateFilter;
//在方法中配置用户名和密码,作为用户登录的数据
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
private static final String[] URL_WHITELIST = {
        "/login.html",
        "/getCode",
        "/hello1"
};

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable();
            // 登录请求url
    http    // 配置拦截规则
            .authorizeRequests()
            //.antMatchers(URL_WHITELIST).permitAll()
            .anyRequest().authenticated()//除了上面的这些请求不需要认证授权,其余全部的都需要认证授权
            .and()
            //设置登陆
            .formLogin()
            .loginProcessingUrl("/login")
            .successHandler(jwtAuthenticationSuccessHandler)
            .failureHandler(authenticationFailHandler)
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            // 配置自定义的过滤器
            .and()
            ///token认证过滤器
            .addFilter(new TokenVerifyFiter(authenticationManager()))
             //图形验证码过滤器
            .addFilterBefore(imageValidateFilter, UsernamePasswordAuthenticationFilter.class);
}


@Bean
public PasswordEncoder passwordEncoder(){
    //加密方式,推荐的方式new BCryptPasswordEncoder();
    return new BCryptPasswordEncoder();
}

/**
 * 1、解决放行资源被token验证过滤器拦截问题
 * 2、WebSecurity主要是配置跟web资源相关的,比如css、js、images等等,但是这个还不是本质的区别,关键的区别如下:
 * ignore是完全绕过了spring security的所有filter,相当于不走spring security,所以ignore只适合配置静态资
 * 源的过滤,不适合api的过滤,过滤api就调用不了api了
 * permitall没有绕过spring security,其中包含了登录的以及匿名的。
 */
@Override
public void configure(WebSecurity web) {
    web.ignoring().antMatchers(URL_WHITELIST);
  }
}
posted @   一条java狗  阅读(119)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示