这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
1.知识点
- 1 认证(authentication) & 鉴权(authorization) 认证:主要是确认身份
授权:授予对系统的访问权限
举个例子:张三登录教务系统,当输入用户名,密码(现在的登录一般都还需要输入验证码等)这是一个认证的过程 若认证成功,进入系统,而对每一种角色有不同的权限,学生只能看自己的成绩,其他同学的成绩不能查看 这就是权限。而今天讲的jwt则可以用来授权
-
2 jwt 定义 JWT(JSON Web Token) 它定义了一种紧凑且自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息.根据这个定义可以看出 传输对象是以json格式。
-
3 应用场景 3.1 jwt可以用来授权 用户登录后 都带上这个jwt 用户则可以访问这个jwt允许的路由,服务,资源。(常见单点登录)
3.2 信息交换 因为jwt可以加密(对称加密:公用一个密钥 非对称加密:使用公钥/私钥),在信息传输的过程中验证信息的真伪性
- 4 结构 jwt结构包含三部分:标题.有效载荷.签名 => xxxx.yyyy.zzzz
头部:一般由两部分组成:令牌类型(jwt);使用的签名算法(如:HMAC,RSA) 并把标题以Base64Url编码形成 JWT 的第一部分
eg:
{ "alg": "HS256", "typ": "JWT" }
有效载荷:简单理解:这里的信息是你想要携带的信息,比如像在jwt携带用户名,登录时间等 都可以再这里加上,但这里的信息最好是非机密信息,因为这个jwt是把相关信息加密了,所以改不容易,但读很容易
eg:其中有注册声明/公共声明
{ "sub": "1234567890", "name": "John Doe", "admin": true }
签名:创建签名部分,就是将前面两个一起加起来 看例子: 如果要使用 HMAC SHA256 算法,则签名将通过以下方式创建,其中secret则是在第一部分使用的签名算法
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
2.代码举例
简单的使用 结合springboot
1.写一个简单的工具类 利用jwt生成token; 验证token
public class JwtUtil {
private String token;
//生成token
public static String CreateToken(TokenInfo tokenInfo){
//对称算法 使用同一个密钥
Algorithm algorithm = Algorithm.HMAC256("secret");
String token = "";
try{
token = JWT.create().withIssuer(tokenInfo.getIssuer())
.sign(algorithm);
}catch (JWTCreationException exception){
throw new UserException("创建token失败:"+exception.getMessage());
}
return token;
}
//对token进行验证
public static void verifyToken(String token){
DecodedJWT decodedJWT = null;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("secret")).build();
decodedJWT = verifier.verify(token);
}catch (Exception e){
throw new UserException("token验证失败");
}
}
}
查看了一下jwt源码:其中JWT.create() JWT.java
JWTCreator.java(对于jwt的生成 主要就在这个java类中调用相应的方法)
当我们在登录的时候就可以直接调用JwtUtil.CreateToken来创建token,当有些功能只能有相应权限的人才能操作 则需要验证用户携带的jwt是否有该权限 JwtUtil.verifyToken
当用户登录后 都带上这个jwt 用户则可以访问这个jwt允许的路由,服务,资源,就例如一个系统,许多操作是必须要登录后才能访问,那我们可以设置一个统一的拦截器来拦截,若未登录就不能访问这些接口,若有自己自定义接口跳过认证则可以不用检查 代码如下:
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
// 如果不是映射到方法直接通过
if (!(handler instanceof HandlerMethod)) return true; // 如果不是映射到方法直接通过
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//检查是否有passtoken验证 若有直接跳过认证 其中passToken是自己自定义的一个注解
if (method.isAnnotationPresent(PassToken.class)){
PassToken annotation = method.getAnnotation(PassToken.class);
if (annotation != null) return true;
}
if (token == null) throw new UserException("无token 请重新登陆");
//验证token
JwtUtil.verifyToken(token);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}