1. 程式人生 > >SpringSecurity使用JWT與前端互動跨域解決後端獲取header中的Authorization的token值

SpringSecurity使用JWT與前端互動跨域解決後端獲取header中的Authorization的token值

主要問題:針對前後端分離後,前端使用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驗證。