浅入深出之了解常见的用户登录校验

[复制链接]
发表于 2024-10-14 15:12:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
前言
   在讲解这个问题之前,我们要先搞清晰基本的用户登录流流程。
  

  • 用户在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当中任何一个字符被篡改,整个令牌都会失效
引入依赖

  1.         <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
  2.                 <dependency>
  3.                         <groupId>io.jsonwebtoken</groupId>
  4.                         <artifactId>jjwt-api</artifactId>
  5.                         <version>0.11.5</version>
  6.                 </dependency>
  7.                 <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
  8.                 <dependency>
  9.                         <groupId>io.jsonwebtoken</groupId>
  10.                         <artifactId>jjwt-impl</artifactId>
  11.                         <version>0.11.5</version>
  12.                         <scope>runtime</scope>
  13.                 </dependency>
  14.                 <dependency>
  15.                         <groupId>io.jsonwebtoken</groupId>
  16.                         <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
  17.                         <version>0.11.5</version>
  18.                         <scope>runtime</scope>
  19.                 </dependency>
复制代码
生成令牌

  1. import io.jsonwebtoken.Claims;
  2. import io.jsonwebtoken.JwtParserBuilder;
  3. import io.jsonwebtoken.Jwts;
  4. import io.jsonwebtoken.io.Decoders;
  5. import io.jsonwebtoken.security.Keys;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.util.StringUtils;
  9. import javax.crypto.SecretKey;
  10. import java.util.Date;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. public class JWTUtil {
  14.     private static final Logger logger = LoggerFactory.getLogger(JWTUtil.class);
  15.     /**
  16.      * 密钥:Base64编码的密钥
  17.      */
  18.     private static final String SECRET = "SDKltwTl3SiWX62dQiSHblEB6O03FG9/vEaivFu6c6g=";
  19.     /**
  20.      * 生成安全密钥:将一个Base64编码的密钥解码并创建一个HMAC SHA密钥。
  21.      */
  22.     private static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(
  23.             Decoders.BASE64.decode(SECRET));
  24.     /**
  25.      * 过期时间(单位: 毫秒)
  26.      */
  27.     private static final long EXPIRATION = 60*60*1000;
  28.     /**
  29.      * 生成密钥
  30.      *
  31.      * @param claim  {"id": 12, "name":"张山"}
  32.      * @return
  33.      */
  34.     public static String genJwt(Map<String, Object> claim){
  35.         //签名算法
  36.         String jwt = Jwts.builder()
  37.                 .setClaims(claim)             // 自定义内容(载荷)
  38.                 .setIssuedAt(new Date())      // 设置签发时间
  39.                 .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) // 设置过期时间
  40.                 .signWith(SECRET_KEY)         // 签名算法
  41.                 .compact();
  42.         return jwt;
  43.     }
  44.     /**
  45.      * 验证密钥
  46.      */
  47.     public static Claims parseJWT(String jwt){
  48.         if (!StringUtils.hasLength(jwt)){
  49.             return null;
  50.         }
  51.         // 创建解析器, 设置签名密钥
  52.         JwtParserBuilder jwtParserBuilder = Jwts.parserBuilder().setSigningKey(SECRET_KEY);
  53.         Claims claims = null;
  54.         try {
  55.             //解析token
  56.             claims = jwtParserBuilder.build().parseClaimsJws(jwt).getBody();
  57.         }catch (Exception e){
  58.             // 签名验证失败
  59.             logger.error("解析令牌错误,jwt:{}", jwt, e);
  60.         }
  61.         return claims;
  62.     }
  63.     /**
  64.      * 从token中获取用户ID
  65.      */
  66.     public static Integer getUserIdFromToken(String jwtToken) {
  67.         Claims claims = JWTUtil.parseJWT(jwtToken);
  68.         if (claims != null) {
  69.             Map<String, Object> userInfo = new HashMap<>(claims);
  70.             return (Integer) userInfo.get("userId");
  71.         }
  72.         return null;
  73.     }
  74. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表