每次請求都會”攜帶“ token( token 在 request 的 header 里面)
攔截驗證過程:
request -> header -> token -> username -> userDetails(getAuthentication()) -> authentication
SecurityContextHolder.getContext().setAuthentication(authentication) //建立安全上下文
代碼
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class); @Autowired private UserDetailsService userDetailsService; @Autowired private JwtTokenUtil jwtTokenUtil; @Value("${jwt.tokenHeader}") private String tokenHeader; @Value("${jwt.tokenHead}") private String tokenHead; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException,IOException { //request 中獲取去 header String authHeader = request.getHeader(this.tokenHeader); //對header做判斷 if (authHeader != null && authHeader.startsWith(this.tokenHeader)) { //取出header //此處注意token之前有一個7字符長度的“Bearer “, String authToken = authHeader.substring(this.tokenHeader.length());// The part after "Bearer " //token中獲取username String username = jwtTokenUtil.getUserNameFromToken(authToken); LOGGER.info("checking username:{}", username); //判斷username if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { //拿到userDetails UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); //驗證token if (jwtTokenUtil.validateToken(authToken,userDetails)) { //完整填充的 authentication(其中包含了權限集 getAuthorities()) UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); LOGGER.info("authenticated user:{}", username); //建立安全上下文 SecurityContextHolder.getContext().setAuthentication(authentication); } } } chain.doFilter(request, response); } }
UserDetails
public interface UserDetails extends Serializable { //用戶的權限集, Collection<? extends GrantedAuthority> getAuthorities(); //用戶的加密后的密碼, 不加密會使用`{noop}`前綴 String getPassword(); //應用內唯一的用戶名 String getUsername(); //賬戶是否過期 boolean isAccountNonExpired(); //賬戶是否鎖定 boolean isAccountNonLocked(); //憑證是否過期 boolean isCredentialsNonExpired(); //用戶是否可用 boolean isEnabled(); }