传统的web应用使用session来维护用户与服务器之间的状态,用户提交用户名密码到服务器,服务器生成会话id,并将验证经过的用户信息存到session中(内存or数据库),会话id会写出到cookie。
用户登陆以后的操做,都会附带包含sessionId的cookie,服务器根据用户端传来的sessionId获取用户信息,会话的有效期,包括用户登出等操做都依赖对session的操做,以下图:
基于session的认证用户信息存在了服务端内存中,在分布式环境中session是须要同步的。出现了基于token的认证方式,其实本质和session没什么区别。用户提交登陆信息后,服务端验证经过后颁发令牌。
下图是以redis为例,将token和用户信息保存到redis,客户端再次访问服务端时,会携带token,服务端经过token获取用户信息。会话的有效期,用户的登出只须要操做redis中的token便可,以下图:
固然了,token自己也是能够包含一些用户非敏感信息减小查库,包含数字签名以防数据篡改,下面看下jwt(json web token)。java
从名称能够看出jwt仍是一个token,它有本身的规范,由标头.有效载荷.签名
组成。头用来描述散列算法,而后是用户数据,最后是一个数字签名。web
先来看下jwt的java实现。redis
dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.2</version> </dependency>
使用jwt一般只须要两个步骤,1经过jwt来生成token,2验证token。算法
public class JwtUtil { private static final String SECRET = "t1o2k3e4n5_s9e8c7r6e5t"; private static final String ISSUER = "star_jwt"; public static String genJwt(Map<String, String> claims) { try { Algorithm algorithm = Algorithm.HMAC256(SECRET); JWTCreator.Builder builder = JWT.create().withIssuer(ISSUER).withExpiresAt(DateUtils.addMinutes(new Date(),30)); claims.forEach(builder::withClaim); return builder.sign(algorithm); } catch (Exception e) { throw new RuntimeException(e); } } public static Map<String, String> verifyToken(String token) { Map<String, String> ret = Maps.newHashMap(); try { Algorithm algorithm = Algorithm.HMAC256(SECRET); JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build(); DecodedJWT jwt = verifier.verify(token); Map<String, Claim> map = jwt.getClaims(); map.forEach((k,v)->ret.put(k,v.asString())); ret.put("exp",map.get("exp").asDate().toString()); } catch (Exception e) { throw new RuntimeException(e); } return ret; } }
以上就是一个jwt的简单示例,客户端携带token请求时,服务端能够校验jwt的签名及有效时间,校验经过则放行,不然拒绝请求。数据库
优势:
能够看到使用jwt自身就能够完成认证,能够减小资源链接,也能够避免跨域认证请求,自带信息也能够用于数据传递。
缺点:
能够看到一旦生成token,就没法回收,token的管理(刷新有效期&登出)须要其它补偿机制(如使用redis管理token);默认有效载荷只是通过base64编码,只是为了方便传输,并未加密(也能够自行加密),敏感数据不该该放到jwt中。json
以为有用,点个关注:
跨域