spring security+jwt 登录认证
1.综述
Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spring 家族中的
成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方
案( 用户认证与用户授权)。
2.版本与环境
idea2022
maven3.6+
jdk1.8
security 5.7.2
3.架构
4.数据库认证逻辑图
5.案例 security+jwt
5.1引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--缺少此jar包,导致@Mapper注解无效-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
5.2新建工具类
JwtUtil
package com.gz.security.utils;
import com.gz.security.config.JwtConfig;
import com.gz.security.constant.Constant;
import com.gz.security.pojo.auth.AccessToken;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.date.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Objects;
/**
* @author: GZ
* @description: JWT 工具类
*
* <p>
* 一个完整的JwtToken由三部分组成:头部+负载信息+签名
* header 存放JwtToken签名的算法 | token的类型:{"alg": "HS512","typ": "JWT"}
* payload 主要存放用户名、创建时间、生成时间:{"sub":"RenHe","created":1489079981393,"exp":1489684781}
* signature 生成算法:HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
* <p>
*/
@Component
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class JwtUtil {
private final JwtConfig jwtConfig;
/**
* 从request中获取token
*
* @param request
* @return
*/
public String getToken(HttpServletRequest request) {
return request.getHeader(Constant.REQUEST_HEADER);
}
/**
* 生成token
*
* @param subject
* @return
*/
public AccessToken generateToken(String subject) {
final Date now = new Date();
Long expired = Long.valueOf(jwtConfig.getExpiredTime());
final Date expiredTime = new Date(now.getTime() + expired * 1000);
String token = Constant.TOKEN_PREFIX + Jwts.builder()
.setSubject(subject)
.setIssuedAt(now)
.setExpiration(expiredTime)
.signWith(SignatureAlgorithm.HS512, jwtConfig.getApiSecretKey())
.compact();
return AccessToken.builder().loginAccount(subject).falconToken(token).expiredTime(expiredTime).build();
}
/**
* 验证token
*
* @param token token from client
* @param username user details from database
*/
public boolean validateToken(String token, String username) {
Claims claims = getClaimsFromToken(token);
return claims.getSubject().equals(username) && !isTokenExpired(claims);
}
/**
* 刷新token
*
* @param oldToken token with tokenHead
*/
public AccessToken refreshToken(String oldToken) {
String token = oldToken.substring(Constant.TOKEN_PREFIX.length());
Claims claims = getClaimsFromToken(token);
if (tokenRefreshJustBefore(claims)) {
return AccessToken.builder().loginAccount(claims.getSubject()).falconToken(oldToken).expiredTime(claims.getExpiration()).build();
} else {
return generateToken(claims.getSubject());
}
}
/**
* 检查token在指定时间内是否被刷新
*/
private boolean tokenRefreshJustBefore(Claims claims) {
Date refreshDate = new Date();
if (refreshDate.after(claims.getExpiration()) && refreshDate.before(DateUtil.offsetSecond(claims.getExpiration(), 1800))) {
return true;
}
return false;
}
/**
* 从token中获取Claims
*
* @param token
* @return
*/
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(jwtConfig.getApiSecretKey())
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
log.error("JWT de-resolve fail, token expired or incorrect, token: {}", token);
}
return claims;
}
/**
* 从token中获取用户信息
*/
public String getSubjectFromToken(String token) {
Claims claims = getClaimsFromToken(token);
if (Objects.nonNull(claims)) {
return claims.getSubject();
} else {
return null;
}
}
/**
* 检查是否过期
*/
private boolean isTokenExpired(Claims claims) {
return claims.getExpiration().before(new Date());
}
}
AuthUtil
package com.gz.security.utils;
import com.gz.security.constant.Constant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
* @author: GZ
* @description: 授权工具类
*/
@Slf4j
public class AuthUtil {
/**
* Retrieve login account from token
*
* @param authToken
* @param jwtProvider
* @return
*/
public static String getLoginAccountFromToken(String authToken, JwtUtil jwtProvider) {
if (StringUtils.isEmpty(authToken) || !authToken.startsWith(Constant.TOKEN_PREFIX)) {
log.info("token is empty or not start with Bearer");
return StringUtils.EMPTY;
}
// 移除token前缀 (Bearer )
authToken = authToken.substring(Constant.TOKEN_PREFIX.length());
// 从token获取登录账户
String loginAccount = jwtProvider.getSubjectFromToken(authToken);
return loginAccount;
}
}
5.2新建组件类
CustomAccessDeniedHandler
package com.gz.security.component;
import com.gz.security.pojo.auth.JsonAuthentication;
import com.gz.security.pojo.response.WebResponseBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author: GZ
* @description: 禁止访问处理 403
*/
@Component
public class CustomAccessDeniedHandler extends JsonAuthentication implements AccessDeniedHandler {
private static final Log logger = LogFactory.getLog(CustomAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e)
throws IOException {
logger.info("Pre-authenticated entry point called. Access denied");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
this.writeJSON(response, WebResponseBuilder.fail("403","禁止访问"));
}
}
CustomAuthenticationEntryPoint
package com.gz.security.component;
import com.gz.security.pojo.auth.JsonAuthentication;
import com.gz.security.pojo.response.WebResponseBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author: GZ
* @description: 未授权处理 401 用来解决匿名用户访问无权限资源时的异常
*/
@Component
public class CustomAuthenticationEntryPoint extends JsonAuthentication implements AuthenticationEntryPoint {
private static final Log logger = LogFactory.getLog(CustomAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2)
throws IOException {
logger.info("Authenticated entry point called. Unauthorized");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
this.writeJSON(response, WebResponseBuilder.fail("401","未授权"));
}
}
CustomAuthenticationFailureHandler
package com.gz.security.component;
import com.gz.security.pojo.auth.JsonAuthentication;
import com.gz.security.pojo.response.WebResponseBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author GuoZhong
* @description 认证失败服务出口
* @date 2022/10/11 10:03
*/
@Slf4j
@Component
public class CustomAuthenticationFailureHandler extends JsonAuthentication implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
response.setStatus(HttpServletResponse.SC_OK);
// 处理异常
if (exception instanceof InternalAuthenticationServiceException) {
this.writeJSON(
response,
WebResponseBuilder.fail(
"500",exception.getMessage()));
} else if (exception instanceof BadCredentialsException) {
this.writeJSON(
response,
WebResponseBuilder.fail(
"500",exception.getMessage()));
} else {
// 输出错误信息
this.writeJSON(
response,
WebResponseBuilder.fail(
"500",exception.getMessage()));
}
}
}
CustomAuthenticationProvider
package com.gz.security.component;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
/**
* @author: GZ
* @date: 2021/9/6 11:11
* @description: 登录身份验证
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
User user=null;
try {
user = (User) userDetailsService.loadUserByUsername(username);
} catch (UsernameNotFoundException e) {
throw new InternalAuthenticationServiceException("用户不存在");
}
return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
CustomAuthenticationSuccessHandler
package com.gz.security.component;
import com.gz.security.config.RedisConfig;
import com.gz.security.constant.RedisKey;
import com.gz.security.pojo.auth.JsonAuthentication;
import com.gz.security.pojo.response.WebResponseBuilder;
import com.gz.security.utils.JwtUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* @author GuoZhong
* @description 登录成功出口
* @date 2022/10/11 10:07
*/
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CustomAuthenticationSuccessHandler extends JsonAuthentication implements AuthenticationSuccessHandler {
private final JwtUtil jwtUtil;
private final RedisTemplate redisTemplate;
private final RedisConfig redisConfig;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
response.setStatus(HttpServletResponse.SC_OK);
User loginAccount = (User) authentication.getPrincipal();
String username = loginAccount.getUsername();
//存储用户信息,设置过期时间
redisTemplate.opsForValue().set(
RedisKey.getLoginAccountKey(username),
loginAccount,
Long.valueOf(redisConfig.getExpiredTime()),
TimeUnit.MINUTES);
// 输出正确响应信息
this.writeJSON(response, WebResponseBuilder.success(jwtUtil.generateToken(username)));
}
}
CustomLogoutSuccessHandler
package com.gz.security.component;
import com.gz.security.constant.RedisKey;
import com.gz.security.pojo.auth.JsonAuthentication;
import com.gz.security.pojo.response.WebResponseBuilder;
import com.gz.security.utils.AuthUtil;
import com.gz.security.utils.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author: RenHe
* @date: 2021/9/6 11:11
* @description: 登出成功处理
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CustomLogoutSuccessHandler extends JsonAuthentication implements LogoutSuccessHandler {
private final JwtUtil jwtUtil;
private final RedisTemplate redisTemplate;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
String authToken = jwtUtil.getToken(request);
String loginAccount = AuthUtil.getLoginAccountFromToken(authToken, jwtUtil);
redisTemplate.delete(RedisKey.getLoginAccountKey(loginAccount));
response.setStatus(HttpServletResponse.SC_OK);
this.writeJSON(response, WebResponseBuilder.success("退出成功"));
}
}
5.3新建配置类
SecurityConfig
package com.gz.security.config;
import com.gz.security.component.*;
import com.gz.security.filter.JwtAuthenticationTokenFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
/**
* @author GZ
* security核心配置类
*/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
/**
* 默认授权白名单
*/
private static final String DEFAULT_AUTH_WHITE_LIST = "/login";
/**
* 用户名
*/
private static final String USERNAME_PARAMETER = "username";
/**
* 密码
*/
private static final String PASSWORD_PARAMETER = "password";
/**
* 登录
*/
private static final String LOGIN = "/login";
/**
* 登出
*/
private static final String LOGOUT = "/logout";
private final CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
private final CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
private final CustomAuthenticationEntryPoint authenticationEntryPoint;
private final CustomAccessDeniedHandler accessDeniedHandler;
private final JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
private final LogoutSuccessHandler customLogoutSuccessHandler;
/**
* 安全认证过滤链配置
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.formLogin()
.loginProcessingUrl(LOGIN)
.usernameParameter(USERNAME_PARAMETER)
.passwordParameter(PASSWORD_PARAMETER)
//成功出口
.successHandler(customAuthenticationSuccessHandler)
//失败出口
.failureHandler(customAuthenticationFailureHandler)
.and()
.logout()
.logoutUrl(LOGOUT)
.clearAuthentication(true)
//退出出口
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
.authorizeRequests()
// 放行所有OPTIONS请求
.antMatchers(HttpMethod.OPTIONS).permitAll()
// 放行白名单地址
.antMatchers(DEFAULT_AUTH_WHITE_LIST).permitAll()
.and()
// 打开Spring Security的跨域,需要新增配置文件
.cors()
.and()
// 关闭CSRF
.csrf().disable()
// 添加未登录与权限不足异常处理器
.exceptionHandling()
//未授权
.authenticationEntryPoint(authenticationEntryPoint)
//禁止访问
.accessDeniedHandler(accessDeniedHandler)
// 将自定义的JWT过滤器放到过滤链中
.and()
.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
// 关闭Session机制
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
/**
* 认证管理器
*/
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
/**
* 加密方式
*/
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
JwtConfig
package com.gz.security.config;
import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author: GZ
* @description: JWT配置
*/
@Configuration
@ConfigurationProperties("jwt")
@Data
@ToString
public class JwtConfig {
/**
* 密钥
*/
private String apiSecretKey = "JWT_SECRET_KEY";
/**
* 过期时间 默认7天
*/
private String expiredTime = "10080";
}
CorsConfig
package com.gz.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.ArrayList;
import java.util.List;
/**
* @author GuoZhong
* @description 跨域请求配置
*/
@Configuration
public class CorsConfig {
/**
* 可跨域请求
*
* @return
*/
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
List<String> allowedOriginPatterns = new ArrayList<>();
allowedOriginPatterns.add("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
AuthenticationConfig
package com.gz.security.config;
import com.gz.security.component.CustomAuthenticationProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
/**
* @author GuoZhong
* @description Authentication 全局配置
* @date 2022/10/16 12:35
*/
@Configuration
@RequiredArgsConstructor
public class AuthenticationConfig extends GlobalAuthenticationConfigurerAdapter {
private final CustomAuthenticationProvider customAuthenticationProvider;
private final UserDetailsService userDetailsService;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.eraseCredentials(false)
.authenticationProvider(customAuthenticationProvider)
.userDetailsService(userDetailsService);
}
}
5.4新建过滤类
JwtAuthenticationTokenFilter
package com.gz.security.filter;
import com.gz.security.constant.Constant;
import com.gz.security.constant.RedisKey;
import com.gz.security.pojo.auth.UserInfo;
import com.gz.security.utils.JwtUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
/**
* @author GZ
* JWT 登录过滤器
*/
@Component
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final RedisTemplate redisTemplate;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain chain)
throws ServletException, IOException {
log.info("JWT filter verification token from request header to auto login start");
// 从请求头获取授权信息
String authToken = jwtUtil.getToken(request);
if (StringUtils.isEmpty(authToken) || !authToken.startsWith(Constant.TOKEN_PREFIX)) {
log.info("Token is empty or not start with Bearer");
chain.doFilter(request, response);
return;
}
// 移除token前缀'Bearer '
authToken = authToken.substring(Constant.TOKEN_PREFIX.length());
// 从token中获取登录用户
String username = jwtUtil.getSubjectFromToken(authToken);
if (StringUtils.isEmpty(username)) {
log.info("Login account is empty");
chain.doFilter(request, response);
return;
}
// 从缓存中获取用户信息
UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(RedisKey.getLoginAccountKey(username));
// 验证token是否过期
if (Objects.isNull(userInfo)) {
log.info("Token is invalid");
chain.doFilter(request, response);
return;
}
// TODO 校验网关 后期放到网关去校验
if (!jwtUtil.validateToken(authToken, userInfo.getUsername())) {
log.info("Token is invalid");
chain.doFilter(request, response);
return;
}
// 创建authentication
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userInfo, userInfo.getPassword(),null);
// 设置authentication到context
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
log.info("JWT filter verification token from request header to auto login successfully end, user : {}", userInfo);
}
}
6.登录访问,接口访问
7.项目地址
https://gitee.com/GZ-jelly/gz-login-spring-boot-starter.git