小声bbb
说到系统的安全识别,记得自己第一个项目,用的就是session,用户登录进来以后,给他session标记登录,记录id进去,轻轻松松,设计的操作也很简单,类似操作HashMap。
这大概也有1年多快两年了,现在回头看真的是可怕,几乎在裸奔
众所周知,平常使用的Session是存储在服务器的一种技术,可以理解为一个会话id,每次使用HTTP请求,都会携带一个sessionId,服务器根据这个SessionId去找对应的session
session一遍是和cookie搭配使用的,cookie是不安全的,毋容置疑(很多浏览器没限制读取),session则是系统生成的一个较长的sessionId,在过期时间内破解session比较困难。
关于session安全性文章,搜一下csdn,很多的
Session安全性
しかし,我预判了你的预判
Session可以理解为是存储在服务器端,key叫sessionId的一个map结构。
Session类似于打电话(没有来电号码显示),在一开始你表明了自己的身份,通话结束后,就失去了效果(实际上使用的是过期的手段)。
当访问的数量增加,记录登录成为一个很大的压力(有记录,有过期操作等,每个人的session信息都要进行维护,且需要存储),是否有一种服务器不用操心的办法?
那么下面就是JWT(或者叫Token)发光发热的舞台了!
只是为了构建JWT请快步到相应的位置
啥是JWT
JWT的全称JSON Web Token
这里我先简单说一下JWT是个啥东西,然后分析为什么好用
JWT可以看做一个身份证,
众所周知,身份证有这几个特性:
- 身份证不能伪造(别动歪脑筋)
- 身份证上有个人信息
- 身份证上有签发机关
- 身份证上有有效期
事实上,这几乎就是JWT了
JWT的特性完全相同,甚至可以用理解身份证的角度来理解他
- 你的网站签发一个令牌(跟我念:身份证)
- 客户端拿着这个令牌找你访问
- 你用你三岁就发明的识别机对令牌(身份证)识别
- 你已经明白他是自己人了,并邀请他一起进来看电视
- 以下为收费项目~~
咳咳,不搞hs,回到正轨,通过我们一本正经的分析,
我们不难发现:Token可以做到在你脸前裸奔,但你却无可奈何
盘点主要特性:
- 存储简单的信息,并且大家都能获取信息
- 无法作假
- 存在过期
其中第一点很重要,token里面的信息是公开的,所以别放密码.
这里插一嘴,jwt里面的信息确实是公开的,只不过大家都进行了二次加密,让人感觉好像jwt里面的信息是不公开的
@某大学某实验室的某学弟
细说JWT
JWT通常情况下是三段,但是也存在一些丧心病狂的,把token又加密了一遍(内行,我直呼内行)
下面是官方给的一个demo(例子)
这个网站也是可以访问的,可以自己试着玩,也可以用来测试
https://jwt.io/
其中很明显为三个部分:HEADER(头部)、PAYLOAD(数据)、VERIFY SIGNATURE(签名)
- 头部:这个token使用了什么加密算法
- 数据:自己定的,想塞什么塞什么,一般有规定的几个内容
- 签名:可以理解为使用秘钥加密后得到的一个不可逆加密(存密码用的很多,原理类似)
其中数据(PAYLOAD)官方定了这几个部分:
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
签名(Signature )部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
JWT 的几个特点
上面用比较形象的方式描述了JWT,下面用官方的话来总结特点
- JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
- JWT 不加密的情况下,不能将秘密数据写入 JWT(个人认为加密了也最好别加吧,秘密的东西最好保持在用后即毁的状态)。
- JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
- JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑(用缓存保存一次签发出去的JWT)。
- JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
- 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
现在来完成一个JWT的实现
详细大家都有maven的经验了
实在不会可以去maven仓库把jar包下载
你用你三岁时就买来的键盘,轻松的使用这个jjwt框架,并老老实实的按照我给的流程感♂受
第一步,导入maven
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
第二步,编写Token的生成逻辑
public static String tokens(Map<String, Object> claims, String secretKey, int millisecond, String jwtIssuer, String jwtAud) {
//获取当前的时间
Calendar calendar = Calendar.getInstance();
Date date = new Date(System.currentTimeMillis());
calendar.setTime(date);
//向后退后秒数
calendar.add(Calendar.MILLISECOND, millisecond);
Date endTime = calendar.getTime();
JwtBuilder builder = Jwts.builder().setClaims(claims)
.signWith(SignatureAlgorithm.HS256, secretKey)
.setClaims(claims)
.setIssuedAt(new Date())
.setExpiration(endTime)
.setIssuer(jwtIssuer)
.setAudience(jwtAud);
return builder.compact();
}
JwtBuilder 是jjwt提供的工具,可以很轻松的构建出一个jwt,利用Builder设计模式,对内容进行定义
其中payload的自定义内容是使用map保存的
编写解密验证的逻辑
public static Claims parse(String jwt, String secretKey) throws JwtExpireException, JwtVerifyException , JwtNotExistException{
Claims claims = null;
try {
claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
} catch (ExpiredJwtException expiredJwtException) {
throw new ExpiredJwtException("token过期");
} catch (JwtException jwtException) {
throw new JwtException("JWT验证错误");
} catch (IllegalArgumentException illegalArgumentException) {
throw new IllegalArgumentException("Token为空");
}
return claims;
}
Claims类就是你的PAYLOAD,可以直接取出信息使用,不抛出异常就视为成功了,如果希望信息隐藏,使用自己的秘钥二次加密即可。
一键三连,支持弟弟
写到这里,就完成了基础的内容了,为了我们用起来更爽,
可以自行进行二次封装,体验更棒