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

文章目录

  • 一、Cookie-Session认证
    • 校验流程
    • 缺点
  • 二、Token
    • 校验流程
    • 缺点
  • 三、JWT
    • 校验流程
  • 四、JWT令牌的实践使用
    • JWT组成
    • 引入依赖
    • 生成令牌

前言

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

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

  1. 用户在web登录页面填写登录信息
  2. 前端发送登录信息到后端
  3. 后端接收登录信息
  4. 后端进行校验
  5. 校验成功,返回成功结果

在本文中会讲解三种常见的登录校验流程
1.Cookie-Session认证
2.

一、Cookie-Session认证

校验流程

  1. 用户在web端输入登录信息
  2. 后端拿到信息后进行校验
  3. 后端校验成功后生成SessionId(这个SessionId关联着用户信息)返回给web
  4. 前端拿到SessionId后就会保存到Cookie中
  5. 在后续的操作中,每次用户访问就会带着着这个Cookie
  6. 后端在后续接收到前端的请求时,就会解析这个SessinId,查询到SessionId关联到的用户信息
  7. 解析成功后,就会根据用户的请求返回响应

流程图如下

缺点

  • Cookie-Session 这种形式只存在于web端
    我们目前更多的使用是在手机端,并不是通过web网页的形式。
  • Cookie不能跨域
  • 不适用于集群环境

二、Token

校验流程

  1. 用户在web端输入登录信息
  2. 后端拿到信息后进行校验
  3. 后端校验成功后生成Toekn(这个Toekn可能是根据用户id生成的,Token关联着用户表)返回给web
  4. 前端拿到后会将Token存储下来
  5. 在后续的操作中,每次用户访问就会带着着这个Token
  6. 后端在后续接收到前端的请求时,就会解析这个Token,查询到关联到的用户信息
  7. 解析成功后,就会根据用户的请求返回响应

流程图如下

缺点

  1. 数据量大,对于内存来说,压力巨大、
    后端在解决集群环境的问题时,将Toekn存储到Redis中,一旦数据量起来,就会对内存造成巨大压力

三、JWT

校验流程

  1. 用户在web端输入登录信息
  2. 后端拿到信息后进行校验
  3. 后端校验成功后生成JWT令牌,返回给web
  4. 前端拿到后会将JWT令牌存储下来
  5. 在后续的操作中,每次用户访问就会带着着这个JWT令牌
  6. 后端在后续接收到前端的请求时,就会解析这个JWT令牌,查询到关联到的用户信息
  7. 解析成功后,就会根据用户的请求返回响应

流程图如下

四、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;
    }
}
版权声明:如无特殊标注,文章均来自网络,本站编辑整理,转载时请以链接形式注明文章出处,请自行分辨。

本文链接:https://www.shbk5.com/dnsj/72377.html