https://blog.csdn.net/Box_clf/article/details/80973391
主要问题:针对前后端分离后,前端使用ajax进行请求,存在一些跨域的问题。
后端对跨域的问题进行解决,因为我是使用的Springboot框架做的后端,首先解决普通请求跨域的问题
@CrossOrigin
每一个controller类上需要添加CrossOrigin的注解进行处理。
添加之后在使用SpringSecurity时允许匿名访问的接口都没有跨域的问题了,不过使用JWT对用户身份进行验证时虽然前端已经将token的值添加到了header中,还是值获取不到header中的token值。
关键的问题就是在这里:
浏览器会在ajax发送请求之前发送一个预请求,确认当请的接口是不是有效的接口,此时的请求方式是OPTIONS的请求方式
因为之前一直没有判断是否是预请求,所以security直接将请求的方式做了正常的处理,导致没有获取到token值所以返回的相应一直是401未授权。这时候就看到前端即使是在头部添加了token但是请求接口一直提示身份认证失败。
需要更改JWT过滤器中的对前端请求的处理方式:
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
//定义的tokenHeader的名称
private String tokenHeader = "Authorization";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
if (request.getMethod().equals("OPTIONS")){
log.info("浏览器的预请求的处理..");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,OPTIONS,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,Content-Type,Accept,Authorization,token");
return;
}else {
String authToken = request.getHeader(this.tokenHeader);
String username = jwtTokenUtil.getUsernameFromToken(authToken);
log.info("checking authentication for user " + username);
//当token中的username不为空是进行验证token是否是有效的token
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
log.info("token中的username不为空,Context中的authentication为空时,进行token的验证..");
//TODO,从数据库得到带有密码的完整user信息
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
log.info("加载userdetails:{}",userDetails.getUsername());
// For simple validation it is completely sufficient to just check the token integrity. You don't have to call
// the database compellingly. Again it's up to you ;)
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
log.info("authenticated user " + username + ", setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
}
}
对第一次的请求进行判断是否是OPTIONS的请求方式,如果是则在对应的response中添加对跨域和header的配置信息
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,OPTIONS,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,Content-Type,Accept,Authorization,token");
如果不是则进行后面的token验证。
---------------------
作者:Box_clf
来源:CSDN
原文:https://blog.csdn.net/Box_clf/article/details/80973391
版权声明:本文为博主原创文章,转载请附上博文链接!