一、认证流程
- UsernamePasswordAuthenticationFilter过滤器用于处理基于表单方式的登录验证,该过滤器默认只有当请求方法为post、请求页面为/login时过滤器才生效,如果想修改默认拦截url,只需在刚才介绍的Spring Security配置类WebSecurityConfig中配置该过滤器的拦截url:.loginProcessingUrl("url")即可;
- BasicAuthenticationFilter用于处理基于HTTP Basic方式的登录验证,当通过HTTP Basic方式登录时,默认会发送post请求/login,并且在请求头携带Authorization:Basic dXNlcjoxOWEyYWIzOC1kMjBiLTQ0MTQtOTNlOC03OThkNjc2ZTZlZDM=信息,该信息是登录用户名、密码加密后的信息,然后由BasicAuthenticationFilter过滤器解析后,构建UsernamePasswordAuthenticationFilter过滤器进行认证;如果请求头没有Authorization信息,BasicAuthenticationFilter过滤器则直接放行;
- FilterSecurityInterceptor的拦截器,用于判断当前请求身份认证是否成功,是否有相应的权限,当身份认证失败或者权限不足的时候便会抛出相应的异常;
- ExceptionTranslateFilter捕获并处理,所以我们在ExceptionTranslateFilter过滤器用于处理了FilterSecurityInterceptor抛出的异常并进行处理,比如需要身份认证时将请求重定向到相应的认证页面,当认证失败或者权限不足时返回相应的提示信息;
二、两种过滤
静态资源过滤
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/index.html", "/img/**", "/fonts/**", "/favicon.ico", "/verifyCode");
}
接口过滤
.antMatchers("/sys_bookmark/**","/sys_code/**","/sys_user/**","/sys_api/**").permitAll()
接口过滤这一块还需要自定义一次过滤器 继承 BasicAuthenticationFilter 的类要放行接口
@Override
protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws IOException, ServletException {
String tokenHeader = request.getHeader(JwtTokenUtil.TOKEN_HEADER);
System.out.println("获取头部数据 >>>> " + tokenHeader);
// 获取请求路径
String requstUrl = request.getRequestURI();
log.info("获取路径 >>> " + requstUrl);
String url1 = ".*/sys_code/.*";
String url2 = ".*/sys_bookmark/.*";
String url3 = ".*/sys_user/.*";
String url4 = ".*/sys_api/.*";
if (Pattern.matches(url1, requstUrl)) {
log.info("获取路径1");
chain.doFilter(request, response);
return;
} else if (Pattern.matches(url2, requstUrl)) {
log.info("获取路径2");
chain.doFilter(request, response);
return;
} else if (Pattern.matches(url3, requstUrl)) {
log.info("获取路径3");
chain.doFilter(request, response);
return;
}else if (Pattern.matches(url4,requstUrl)) {
log.info("获取路径4");
chain.doFilter(request, response);
return;
}
// 若请求头中没有Authorization信息 或是Authorization不以Bearer开头 则直接放行
if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX)) {
log.info("请求未通过");
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("code",2003);
map.put("message","您未登录请先登录");
writer.write(JSON.toJSONString(map));
return;
}
// 去掉前缀 获取Token字符串
String token = tokenHeader.replace(JwtTokenUtil.TOKEN_PREFIX, "");
// 校验token有效时间
if (JwtTokenUtil.isExpiration(token)){
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("code",3000);
map.put("message","token已失效");
writer.write(JSON.toJSONString(map));
return;
}
// 若请求头中有token 则调用下面的方法进行解析 并设置认证信息
SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader));
super.doFilterInternal(request, response, chain);
}