电商常见等用户信息校验等方法:
方案2:用户量大时,带宽等占用严重
1、单机tomcat应用登录检验
sesssion保存在浏览器和应用服务器会话之间
用户登录成功,服务端会保证一个session,当然会给客户端一个sessionId,
客户端会把sessionId保存在cookie中,每次请求都会携带这个sessionId
2、分布式应用中session共享
真实的应用不可能单节点部署,所以就有个多节点登录session共享的问题需要解决
1)tomcat支持session共享,但是有广播风暴;用户量大的时候,占用资源就严重,不推荐
2)使用redis存储token:
服务端使用UUID生成随机64位或者128位token,放入redis中,然后返回给客户端并存储在cookie中
用户每次访问都携带此token,服务端去redis中校验是否有此用户即可
Jwt技术解决上面等问题:
1、JWT 是一个开放标准,它定义了一种用于简洁,自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。
JWT 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名
简单来说,就是通过一定规范来生成token,然后可以通过解密算法逆向解密token,这样就可以获取用户信息
{
id:888,
name:'小D',
expire:10000
}
funtion 加密(object, appsecret){
xxxx
return base64( token);
}
function 解密(token ,appsecret){
xxxx
//成功返回true,失败返回false
}
优点:
1)生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库
2)存储在客户端,不占用服务端的内存资源
缺点:
token是经过base64编码,所以可以解码,因此token加密前的对象不应该包含敏感信息
如用户权限,密码等
2、JWT格式组成 头部、负载、签名
header+payload+signature
头部:主要是描述签名算法
负载:主要描述是加密对象的信息,如用户的id等,也可以加些规范里面的东西,如iss签发者,exp 过期时间,sub 面向的用户
签名:主要是把前面两部分进行加密,防止别人拿到token进行base解密后篡改token
3、关于jwt客户端存储
可以存储在cookie,localstorage和sessionStorage里面
- 加入相关依赖
- 编写生成token
- 编写检验token
相关依赖
<!--jwt的依赖 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.8.0</version> </dependency>
public class JwtUtils { private static final String JWTSECRET = "myScrect"; /* 生成token的方法 */ public static String create(User user) { if (user == null || user.getId() == null || user.getUserName() == null) { return null; } String token = Jwts.builder() .setSubject(JWTSECRET) //设置签名 .claim("id", user.getId()) //设置传入的参数 .claim("name", user.getUserName()) .setIssuedAt(new Date()) //发行时间 .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7)) //过期时间 .signWith(SignatureAlgorithm.HS256, JWTSECRET) //签名算法 ,密钥 ES256报错见下面 .compact(); //压缩 return token; } /** * 校验token * * @param token 传入的令牌 * @return */ public static Claims checkJWT(String token) { //通常如果伪造或token过期都会抛出异常所有包裹一下 try { final Claims claims = Jwts.parser() .setSigningKey(JWTSECRET) // .parseClaimsJws(token) .getBody(); //可以得到签名getSignature getHeader头部 // if (claims.get("id")==null) return claims; } catch (Exception e) { e.printStackTrace(); } return null; }
RS256 (采用SHA-256 的 RSA 签名) 是一种非对称算法, 它使用公共/私钥对: 标识提供方采用私钥生成签名, JWT 的使用方获取公钥以验证签名。由于公钥 (与私钥相比) 不需要保护, 因此大多数标识提供方使其易于使用方获取和使用 (通常通过一个元数据URL)。
另一方面, HS256 (带有 SHA-256 的 HMAC 是一种对称算法, 双方之间仅共享一个 密钥。由于使用相同的密钥生成签名和验证签名, 因此必须注意确保密钥不被泄密。
在开发应用的时候启用JWT,使用RS256更加安全,你可以控制谁能使用什么类型的密钥。另外,如果你无法控制客户端,无法做到密钥的完全保密,RS256会是个更佳的选择,JWT的使用方只需要知道公钥。
测试
@Test public void TestJWT(){ User user = new User(); user.setId(1); user.setUserName("xijie"); String token = JwtUtils.create(user); System.out.println(token); }
开始报错
java.lang.IllegalArgumentException: Base64-encoded key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.
将ES256改为HS256 加密算法
拿到token生成token成功
@Test public void TestCheck(){ String token="eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJteVNjcmVjdCIsImlkIjoxLCJuYW1lIjoieGlqaWUiLCJpYXQiOjE1NTA3MjAxMTcsImV4cCI6MTU1MTMyNDkxN30.ovDf7015iSwMHlBVk0D8FQXhVTNVuZOSrs4dKXZMKSw"; Claims claims = JwtUtils.checkJWT(token); System.out.println(""+claims); if (claims!=null){ Integer id = (Integer) claims.get("id"); String name = (String) claims.get("name"); System.out.println(id+name); } }
测试Ok