JAVA使用JWT生成token"/>
JAVA使用JWT生成token
定义
JWT(JSON Web Token)简而言之,JWT是一个加密的字符串,JWT传输的信息经过了数字签名,因此传输的信息可以被验证和信任。一般被用来在身份提供者和服务提供者间传递被认证用户的身份信息,以便于从资源服务器获取资源,也可以增加一些额外的业务逻辑所需的声明信息。
验证流程
使用基于Token的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
- 客户端使用用户名和密码请求登录
- 服务端收到请求,去验证用户名和密码
- 验证成功后,服务端会签发一个Token,再把这个Token发送给客户端
- 客户端收到Token以后可以把它存储起来,比如放到Cookie里或者Local Storage里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的Token
- 服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据
组成部分
JWT 标准的 Token 由三个部分组成:header.payload.signature:
header(头部)
payload(数据)
signature(签名)
Header
头部数据,里面包含了使用的算法。
声明类型,这里是jwt
声明加密的算法 通常直接使用 HS256
{"alg": "HS256","typ": "JWT"
}
在base64url编码之后变成
eyJhbGciOiJIUzI1NiJ9
playload
载荷是存放有效信息的地方。
iss: Issuer,发行者
sub: Subject,主题
aud: Audience,观众
exp: Expiration time 过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
可以自定义字段, 一个是 id ,还有一个是 admin 。
{"iss": "ninghao","exp": "1438955445","id": "aaa","admin": true
}
使用 base64url 编码以后就变成了这个样子:
eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ
signature
一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密。
const encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload);
// 这里的 HMACSHA256() 就是我们在第一部分定义的加密算法。
HS256(encodedString, 'secret');
处理完像这样
SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
最后这个在服务端生成并且要发送给客户端的 Token
eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
客户端收到这个 Token 以后把它存储下来,下回向服务端发送请求的时候就带着这个 Token。服务端收到这个 Token ,然后进行验证,通过以后就会返回给客户端想要的资源。
代码如下
相关依赖
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version></dependency>
token生成和验证
public class TokenUtil {/*** token过期时间*/private static final long EXPIRE_TIME = 30 * 60 * 1000;/*** token秘钥*/private static final String SECRET = "demo_secret";/*** 生成签名,30分钟过期* @param username 用户名* @param loginTime 登录时间* @return 生成的token*/public static String sign(String username, String loginTime) {try {// 设置过期时间Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);// 私钥和加密算法Algorithm algorithm = Algorithm.HMAC256(SECRET);// 设置头部信息Map<String, Object> header = new HashMap<>(2);header.put("Type", "Jwt");header.put("alg", "HS256");// 返回token字符串return JWT.create().withHeader(header).withClaim("loginName", username).withClaim("loginTime", loginTime).withExpiresAt(date).sign(algorithm);} catch (Exception e) {e.printStackTrace();return null;}}/*** 检验token是否正确* @param token 需要校验的token* @return 校验是否成功*/public static boolean verify(String token){try {//设置签名的加密算法:HMAC256Algorithm algorithm = Algorithm.HMAC256(SECRET);JWTVerifier verifier = JWT.require(algorithm).build();DecodedJWT jwt = verifier.verify(token);return true;} catch (Exception e){return false;}}
}
登录
/*** 登录* @param loginVo 登录类* @return 返回类*/@Overridepublic R login(LoginVo loginVo) {User user = new User();user.setUserName(loginVo.getUserName());user.setPassword(loginVo.getPassword());List<User> users = userService.queryByUser(user);if(users.isEmpty()){return R.fail();}else{if(loginVo.getUserName() != null && loginVo.getLoginTime() != null) {String token = TokenUtil.sign(loginVo.getUserName(), loginVo.getLoginTime());loginVo.setToken(token);//断言token不为空,并以用户名作为key,存入redis(看需求是否要放到redis)assert token != null;redisTemplate.opsForValue().set(loginVo.getUserName(),token);return R.ok(loginVo);}else{return R.fail();}}}
添加拦截器类
@Component
public class TokenInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if ("OPTIONS".equals(request.getMethod())) {response.setStatus(HttpServletResponse.SC_OK);return true;}response.setCharacterEncoding("utf-8");String token = request.getHeader("Authorization");if (token != null) {boolean result = TokenUtil.verify(token);if (result) {System.out.println("通过拦截器");return true;}}response.setCharacterEncoding("UTF-8");response.setContentType("application/json; charset=utf-8");PrintWriter out = null;try {JSONObject json = new JSONObject();json.put("success", "false");json.put("msg", "认证失败,未通过拦截器");json.put("code", "500");response.getWriter().append(json.toJSONString());System.out.println("认证失败,未通过拦截器");} catch (Exception e) {e.printStackTrace();response.sendError(500);return false;}return false;}
}
添加配置拦截器的类
@Component
public class IntercepterConfig implements WebMvcConfigurer {private TokenInterceptor tokenInterceptor;//构造方法public IntercepterConfig(TokenInterceptor tokenInterceptor){this.tokenInterceptor = tokenInterceptor;}@Overridepublic void addInterceptors(InterceptorRegistry registry){List<String> excludePath = new ArrayList<>();//登录excludePath.add("/login/acount");registry.addInterceptor(tokenInterceptor).addPathPatterns("/**").excludePathPatterns(excludePath);//除了登陆接口其他所有接口都需要token验证WebMvcConfigurer.super.addInterceptors(registry);}}
参考博客:
.html
更多推荐
JAVA使用JWT生成token
发布评论