马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
前言
在讲解这个问题之前,我们要先搞清晰基本的用户登录流流程。
- 用户在web登录页面填写登录信息
- 前端发送登录信息到后端
- 后端吸收登录信息
- 后端进行校验
- 校验乐成,返回乐成效果
在本文中会讲解三种常见的登录校验流程
1.Cookie-Session认证
2.
一、Cookie-Session认证
校验流程
- 用户在web端输入登录信息
- 后端拿到信息后进行校验
- 后端校验乐成后生成SessionId(这个SessionId关联着用户信息)返回给web
- 前端拿到SessionId后就会生存到Cookie中
- 在后续的操纵中,每次用户访问就会带着着这个Cookie
- 后端在后续吸收到前端的哀求时,就会解析这个SessinId,查询到SessionId关联到的用户信息
- 解析乐成后,就会根据用户的哀求返回响应
流程图如下
缺点
- Cookie-Session 这种形式只存在于web端
我们目前更多的使用是在手机端,并不是通过web网页的形式。
- Cookie不能跨域
- 不适用于集群情况
二、Token
校验流程
- 用户在web端输入登录信息
- 后端拿到信息后进行校验
- 后端校验乐成后生成Toekn(这个Toekn可能是根据用户id生成的,Token关联着用户表)返回给web
- 前端拿到后会将Token存储下来
- 在后续的操纵中,每次用户访问就会带着着这个Token
- 后端在后续吸收到前端的哀求时,就会解析这个Token,查询到关联到的用户信息
- 解析乐成后,就会根据用户的哀求返回响应
流程图如下
缺点
- 数据量大,对于内存来说,压力巨大、
后端在办理集群情况的问题时,将Toekn存储到Redis中,一旦数据量起来,就会对内存造成巨大压力
三、JWT
校验流程
- 用户在web端输入登录信息
- 后端拿到信息后进行校验
- 后端校验乐成后生成JWT令牌,返回给web
- 前端拿到后会将JWT令牌存储下来
- 在后续的操纵中,每次用户访问就会带着着这个JWT令牌
- 后端在后续吸收到前端的哀求时,就会解析这个JWT令牌,查询到关联到的用户信息
- 解析乐成后,就会根据用户的哀求返回响应
流程图如下
四、JWT令牌的实践使用
JWT构成
JWT由三部分构成, 每部分中央使⽤点 (.) 分隔,⽐如:aaaaa.bbbbb.cccc
- Header(头部) 头部包罗令牌的范例(即JWT)及使用的哈希算法(如SHA256)
- Payload(负载) 负载部分是存放有效信息的地⽅, ⾥⾯是⼀些⾃定义内容
- Signature(签名) 此部分⽤于防⽌jwt内容被篡改,确保安全性
JWT之所以安全,就是由于这个签名,JWT当中任何一个字符被篡改,整个令牌都会失效
引入依赖
- <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-api</artifactId>
- <version>0.11.5</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-impl</artifactId>
- <version>0.11.5</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
- <version>0.11.5</version>
- <scope>runtime</scope>
- </dependency>
复制代码 生成令牌
- import io.jsonwebtoken.Claims;
- import io.jsonwebtoken.JwtParserBuilder;
- import io.jsonwebtoken.Jwts;
- import io.jsonwebtoken.io.Decoders;
- import io.jsonwebtoken.security.Keys;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.util.StringUtils;
- import javax.crypto.SecretKey;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Map;
- public class JWTUtil {
- private static final Logger logger = LoggerFactory.getLogger(JWTUtil.class);
- /**
- * 密钥:Base64编码的密钥
- */
- private static final String SECRET = "SDKltwTl3SiWX62dQiSHblEB6O03FG9/vEaivFu6c6g=";
- /**
- * 生成安全密钥:将一个Base64编码的密钥解码并创建一个HMAC SHA密钥。
- */
- private static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(
- Decoders.BASE64.decode(SECRET));
- /**
- * 过期时间(单位: 毫秒)
- */
- private static final long EXPIRATION = 60*60*1000;
- /**
- * 生成密钥
- *
- * @param claim {"id": 12, "name":"张山"}
- * @return
- */
- public static String genJwt(Map<String, Object> claim){
- //签名算法
- String jwt = Jwts.builder()
- .setClaims(claim) // 自定义内容(载荷)
- .setIssuedAt(new Date()) // 设置签发时间
- .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) // 设置过期时间
- .signWith(SECRET_KEY) // 签名算法
- .compact();
- return jwt;
- }
- /**
- * 验证密钥
- */
- public static Claims parseJWT(String jwt){
- if (!StringUtils.hasLength(jwt)){
- return null;
- }
- // 创建解析器, 设置签名密钥
- JwtParserBuilder jwtParserBuilder = Jwts.parserBuilder().setSigningKey(SECRET_KEY);
- Claims claims = null;
- try {
- //解析token
- claims = jwtParserBuilder.build().parseClaimsJws(jwt).getBody();
- }catch (Exception e){
- // 签名验证失败
- logger.error("解析令牌错误,jwt:{}", jwt, e);
- }
- return claims;
- }
- /**
- * 从token中获取用户ID
- */
- public static Integer getUserIdFromToken(String jwtToken) {
- Claims claims = JWTUtil.parseJWT(jwtToken);
- if (claims != null) {
- Map<String, Object> userInfo = new HashMap<>(claims);
- return (Integer) userInfo.get("userId");
- }
- return null;
- }
- }
复制代码 |