在进行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);
}
}
标签:拦截器,登录,private,token,失败,new,security,public
From: https://www.cnblogs.com/syq520/p/17368679.html