开发记录:基于JWT生成token
开发记录:基于JWT生成token
Token
Token用于验证用户登录,传统的基于cookie的session认证已经满足不了需求了。服务器端可以设置token的生成规则以及有效时间,每当进行登录判断的时候,服务器就查看这个token是不是按照服务器约定的生成规则生成的token,以此来校验用户登录。
Token与cookie相比较的优势
(来源百度)
1、支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的;
2、无状态化,服务端无需存储token,用户端在cookie中存放token,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session;
3、无需绑定到一个特殊的身份验证方案(传统的用户名密码登陆),只需要生成的token是符合我们预期设定的即可;
4、更适用于移动端(Android,iOS,小程序等等),像这种原生平台不支持cookie,比如说微信小程序,每一次请求都是一次会话,当然我们可以每次去手动为他添加cookie
5、非常适用于RESTful API,这样可以轻易与各种后端(java,.net,python......)相结合,去耦合
流程图
来源于 博客园-黄进广寒
流程简洁版:
- 用户使用用户名密码来请求服务器
- 服务器进行验证用户的信息
- 服务器通过验证发送给用户一个token
- 客户端存储token,并在每次请求时附送上这个token值
- 服务端验证token值,并返回数据
JWT工具
- JWT(Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。
- JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上
- JWT最重要的作用就是对 token信息的防伪作用。
- JWT的原理:
- 一个JWT由三个部分组成:公共部分(JWT头)、私有部分(有效载荷)、签名部分。最后由这三者组合进行 base64编码 得到JWT
- base64编码,并不是加密,只是把明文信息变成了不可见的字符串。但是其实只要用一些工具就可以把base64编码解成明文,所以不要在JWT中放入涉及私密的信息。
代码
// 生成token的工具类,固定写法
public class JwtHelper {
//过期时间
private static long tokenExpiration = 24*60*60*1000;
//签名秘钥
private static String tokenSignKey = "123456";
//根据参数生成token,三部分组成,用 . 隔开
public static String createToken(Long userId, String userName) {
String token = Jwts.builder()
.setSubject("USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)) // 公共部分结束
.claim("userId", userId)
.claim("userName", userName) // 私有部分,实际上真正需要封装的信息(id和name)
.signWith(SignatureAlgorithm.HS512, tokenSignKey) // 签名部分
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
//根据token字符串得到用户id
public static Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
//根据token字符串得到用户名称
public static String getUserName(String token) {
if(StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String)claims.get("userName");
}
// 测试
public static void main(String[] args) {
String token = JwtHelper.createToken(1L, "lucy");
System.out.println(token);
System.out.println(JwtHelper.getUserId(token));
System.out.println(JwtHelper.getUserName(token));
}
}
安全相关
不要在JWT的有效载荷部分存放敏感信息,因为该部分是客户端可解密的部分。