准备工作
链接: SpringSecurity准备(依赖+配置类+工具类)
jwtFilter的实现
该过滤器要继承OncePerRequestFilter同时必须重写里面的doFilterInternal方法
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
}
}
先获取请求头中的token信息
根据token是否为NULL判断用户的该请求是否需要登录(如果请求头中有token说明该请求需要登录,没有token信息表示该请求不需要登录就可以访问)
解析获取userId
通过Jwt工具类解析Jwt,解析的同时也要判断token是否超时或者无效,这时就需要提示用户需要重新登录
从redis中获取用户信息
通过redisCache.getCacheObject 根据Key值在redis中找到用户信息(LoginUser)
//获取请求中的token
String token = httpServletRequest.getHeader("token");
if(!StringUtils.hasText(token)){
//说明该接口不需要登录
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
//解析获取UserId
Claims claims =null;
try {
claims = JwtUtil.parseJWT(token);
} catch (Exception e) {
e.printStackTrace();
//token超时,token非法
ResponseResult r = ResponseResult.errorResult(401, "需要登录");
WebUtils.renderString(httpServletResponse, JSON.toJSONString(r));
return;
}
String UserId = claims.getSubject();
LoginUser loginUser = redisCache.getCacheObject("LoginUser:" + UserId);
存入SpringSecurityContextHolder
//存入SecurityContextHolder
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null);
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
//放行
filterChain.doFilter(httpServletRequest, httpServletResponse);
在SpingSecurity的配置类Config中进行配置
注入JwtAuthenticationTokenFilter
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
添加过滤器
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
完整的配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
//暴露ProvideManger方法
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//关闭csrf
.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 对于登录接口 允许匿名访问
.antMatchers("/login").anonymous()
//以下接口都需要携带token访问
// .antMatchers("/logout").authenticated()
// 除上面外的所有请求全部不需要认证即可访问
.anyRequest().permitAll();
//允许跨域
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
http.logout().disable();
http.cors();
}
}
工具类:
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static void renderString(HttpServletResponse response, String string) {
try
{
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
}
catch (IOException e)
{
e.printStackTrace();
}
}