1.JWT
JWT(JSON Web Token)是一种开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间作为令牌传递信息。这个令牌可以用于认证和授权,也可以用于在各方之间传递信息。
一个JWT主要包括三个部分:头部(Header)、负载(Payload)和签名(Signature)。
头部(Header):这是一个JSON对象,描述了将要被签名的数据使用的算法类型,比如 "HS256" 代表 HMAC SHA-256 签名算法。
负载(Payload):这是一个JSON对象,包含了要发送的数据。这些数据可以是用户ID、角色、用户名等。
签名(Signature):这是对头部和负载进行签名后的结果,用来保证头部和负载的完整性和真实性。签名是通过对头部和负载进行散列,然后用一个密钥生成一个签名值。
使用base64进行编码:
Base64URL(header).Base64URL(payload).Base64URL(signature)
2.使用思路介绍
用户登录之后生成JWT令牌,并将令牌存到redis以及发送给用户,用户每次请求都包含JWT令牌服务器进行验证。
3.使用代码
3.1 安装环境
需要在springboot中安装包:
implementation 'com.auth0:java-jwt:4.4.0'
implementation 'org.springframework.boot:spring-boot-starter-data-redis:2.5.14'
3.2 JWT令牌生成及校验
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtils {
//加密密钥
public static final String KEY="123456";
//生成JWT令牌
public static String createJWT(Map<String, Object> json){
return JWT.create()
.withClaim("claims",json)
.withExpiresAt(new Date(System.currentTimeMillis()+1000*3600*12))
.sign(Algorithm.HMAC256(KEY));
}
//验证JWT令牌
public static Map<String,Object> verifyJWT(String token){
return JWT.require(Algorithm.HMAC256(KEY)).build()
.verify(token)
.getClaim("claims")
.asMap();
}
}
3.3 全局请求进行验证
登录拦截器(Interceptor):
import com.example.videoplay.utils.JwtUtils;
import com.example.videoplay.utils.Result;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override //目标资源方法运行前运行, 返回true: 放行, 放回false, 不放行
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
String url = req.getRequestURL().toString();
System.out.println("请求的url: "+url);
if(url.contains("login")||url.contains("register")){
System.out.println("登录操作, 放行...");
return true;
}
String jwt = req.getHeader("token");
//从redis获取相同的token
ValueOperations<String,String> operations=stringRedisTemplate.opsForValue();
if(!StringUtils.hasLength(jwt)){
System.out.println("请求头token为空,返回未登录的信息");
Result error = new Result().error("NOT_LOGIN");
String notLogin = error.toString();
resp.getWriter().write(notLogin);
return false;
}
//先从redis中查看是否有该密钥,再尝试进行解密
try {
String redisToken=operations.get(jwt);
if(redisToken==null){
throw new RuntimeException();
}
JwtUtils.verifyJWT(jwt);
} catch (Exception e) {//jwt解析失败
e.printStackTrace();
System.out.println("解析令牌失败, 返回未登录错误信息");
Result error = new Result().error("NOT_LOGIN");
//手动转换 对象--json --------> 阿里巴巴fastJSON
String notLogin = error.toString();
resp.getWriter().write(notLogin);
return false;
}
System.out.println("令牌合法, 放行");
return true;
}
@Override //目标资源方法运行后运行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ...");
}
@Override //视图渲染完毕后运行, 最后运行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
3.4 redis数据存取
存数据:
@Autowired
private StringRedisTemplate stringRedisTemplate;
ValueOperations<String,String> operations=stringRedisTemplate.opsForValue();
operations.set(token,token,12, TimeUnit.HOURS);
取数据:
String redisToken=operations.get(jwt);
删除数据:
operations.getOperations().delete(token);