在安全配置文件MySecurityConfig.java里配置了两个过滤器LoginFilter和JwtAuthenticationTokenFilter。
1、用户请求进来时,首先调用JwtAuthenticationTokenFilter过滤器,检查是否携带token,如果已有token,则验证token是否合法,如果合法,则直接通过验证。如果没有携带token,或者token不合法,则会进入下一个过滤器,即身份验证过滤器。以下是JwtAuthenticationTokenFilter过滤器代码:
package com.security; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import com.service.MyUserDetailsService; @Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter{ @Autowired MyUserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { //请求头为 Authorization //请求体为 Bearer token String authHeader = request.getHeader("Authorization"); //获取请求头 if (authHeader != null && authHeader.startsWith("Bearer ")) { //如果请求头不为空,且以Bearer 开头 final String authToken = authHeader.substring("Bearer ".length()); //获取令牌 String username = JwtTokenUtils.parseToken(authToken); //从令牌中获取用户名 if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { //如果用户认证信息不为空 UserDetails userDetails = userDetailsService.loadUserByUsername(username); if (userDetails != null) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } } chain.doFilter(request, response); //请求头为空,或重新认证不通过,则直接进入下一个过滤链 } }View Code
2、用户第一次登录时(无token)或者token不合法时,将调用身份验证过滤器,即LoginFilter。
package com.security; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; public class LoginFilter extends UsernamePasswordAuthenticationFilter{ String username; String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } }View Code
身份验证主要是通过改写Authentication方法,通过以下3行代码即完成用户名和密码校验,这是标准的身份校验方法,切不可直接根据加密算法算出加密密文,然后再比较密文是否与数据库中的密文相同这样的方法。
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest);