在应用的登录时需要生成token进行验证,并放入信息,之后的话可以直接使用浏览器的session(有时候可能会出现session共享以及丢失问题,这个时候可以使用Redis因为Redis一般集群)进行登录,获取信息,进行直接登录
这边写了一个token工具类,可以很方便的生成和解析token,代码如下
加依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version> <!-- 请根据最新版本更新 -->
</dependency>
写工具类
public class JwtUtils {
public static final long DEFAULT_TTL = 30 * 24 * 60 * 60 * 1000L; // 30天
public static final String DEFAULT_PLAIN_TEXT = "dbmzlh";
/**
* 生成UUID,也可以为雪花算法
* @return
*/
public static String generateUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
/**
* 生成token令牌,数据为默认的
* @return
*/
public static String generateJWT() {
return generateJWT(DEFAULT_PLAIN_TEXT, DEFAULT_TTL);
}
/**
* 传入JSON对象生成令牌
* @param subject
* @return
*/
public static String generateJWT(String subject) {
return generateJWT(subject, DEFAULT_TTL);
}
/**
* token 生成器
* @param subject 信息
* @param ttlMillis 有效时间
* @return 令牌
*/
public static String generateJWT(String subject, Long ttlMillis) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
SecretKey secretKey = generalKey(); // 生成适用于 HMAC 的密钥
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
if (ttlMillis == null) {
ttlMillis = DEFAULT_TTL;
}
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
return Jwts.builder()
.setId(generateUUID()) //唯一ID
.setSubject(subject) //JSON对象
.setIssuer("dabaimao") //签发人
.setIssuedAt(now) //签发时间
.signWith(signatureAlgorithm, secretKey) // 使用密钥进行签名
.setExpiration(expDate)
.compact();
}
/**
* 使用AES算法生成公私钥
* @return
*/
public static SecretKey generalKey()
{
byte[] encodedKey = Base64.getDecoder().decode(DEFAULT_PLAIN_TEXT.replace("\r\n", ""));
return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
}
/**
* 解析token令牌
* @param jwt 令牌
* @return 对象
* @throws Exception
*/
public static Claims analysisJWT(String jwt) throws Exception
{
SecretKey secretKey = generalKey();
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
}
public static void main(String[] args) throws Exception {
String jwtToken = generateJWT("大白猫真厉害", DEFAULT_TTL);
System.out.println("登录成功生成的token: " + jwtToken);
//也可以网页解析token,网址https://jwt.io
System.out.println("解析token得到的数据: "+analysisJWT(jwtToken).toString());
}
}
结果如下:
登录流程
第一次登录后前端将登录成功返回的token放到session中,之后每一次登录都携带session,到服务器解析生成对应的登录者数据,可以查询数据库并执行将数据放到Redis的一些操作,后端可以使用网关的过滤以及拦截去实现登录功能
拦截器实例
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ToKenFilter())
.addPathPatterns("","") //拦截那些路径
.excludePathPatterns(""); //放行那些路径
}
}
在TokenFilter中处理逻辑,根据放入的数据查询Redis找到对应的人物
比如toKen免密登录解析出为user:001根据拿到的数据去数据库查询人物信息,放到Redis中
(权限验证:轻松实现权限验证 大白猫~的博客)
@Component
public class ToKenFilter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 2. 解码JWT令牌
try {
// 1. 从HTTP请求头部获取JWT令牌
String jwtToken = request.getHeader("token");
// 请替换下面的方法和密钥为你实际使用的JWT库和密钥
Claims claims = JwtUtils.analysisJWT(jwtToken);
// 3. 验证JWT令牌
// 3.1 签名验证已经在解码中完成
// 3.2 过期验证
Date expirationDate = claims.getExpiration();
Date now = new Date();
if (expirationDate.before(now)) {
// 令牌已过期,发送错误响应
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
// 3.3 权限验证,根据需要执行
} catch (Exception e) {
// 令牌无效或解码失败,发送错误响应
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
// 验证通过,返回true,请求继续到达控制器方法
return true;
}
}
这样就可以了
流程图