2.3.3.4 认证过滤器
我们需要自定义一个过滤器,这个过滤器会去获取请求头中的token,对token进行解析取出其中的userid。
使用userid去redis中获取对应的LoginUser对象。
然后封装Authentication对象存入SecurityContextHolder。
package filter;
import ...
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
@Autowired
private RedisCache redisCache;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain
filterChain) throws ServletException, IOException {
//直接放行不等于不设置SecurityContextHolder,不设置SecurityContextHolder就没法通过认证到达Api,会被后面的filter给拦住
//获取请求头中的token
String token = request.getHeader("token");
if(!Stringutils.hasText(token)){
//放行
filterchain.doFilter(request,response);
//过滤器中doFilter方法前面的逻辑是请求进来时执行的内容,doFilter后面的逻辑是响应时执行的内容,直接return了,响应时就不会执行后面的内容了
return;
}
//解析token获取userid
string userId;
try {
Claims claims = JwtUtil.parseJWT(token);
userId = claims.getsubject();
} catch(Exception e) {
e.printStackTrace();
throw new RuntimeException("token非法");
}
//通过 userId 从redis中获取用户信息
String redisKey = "login:"+userId;
LoginUser loginUser = redisCache.getCacheObject(redisKey);
if(Object.isNull(loginUser)) {
throw new RuntimeException("用户未登录");
}
//如果从redis中获取到loginUser,就存入SecurityContextHolder
//TODO 获取权限信息封装到Authentication中
//前面登录时用两参,对认证状态还未确认,之后调用ProviderManager对账号密码进行确认后,返回的那个Authentication是认证的。
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, null); //目前没有权限信息,所以为null,后面会加上
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//放行
filterchain.doFilter(request,response);
}
}
上面的代码与之前登陆的代码相比较,可以发现为什么之前UsernamePasswordAuthenticationToken存的是username和password,而这里存的是loginUser和null呢?
我们可以分别点进去看看这两个方法虽然名字一样但是传入参数不一样的。一个是已认证的,一个是未认证的,结构不一样;同时,一个是登录,一个是验证两个场景,不能混在一起看。可以这么理解,之前的是登陆时验证,后面的这个是登录后访问验证。
接下来的话我们就需要添加相关过滤器的coonfig配置,由于security提供了这个方法,我们还是和之前一样写在SecurityConfig文件中,通过在 configure 方法内部加上如下代码即可实现。
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter
@Overrride
protected void configure(HttpSecurity http) throws Exception {
//之前的代码
...
//新增加的过滤器代码,需要传入两个对象,一个文档对象,一个字节码对象(指定添加到哪个过滤器对象之前)
http.addFilterBefore(jwtAuthenticationTokenFilter,UsernamePasswordAuthenticationFilter.class);
}
评论