JWT令牌

在我们实现登录的时候:

传统思路:

  • 登录页面把用户名密码提交给服务器
  • 服务器验证用户名密码是否正确,并返回校验结果给后端
  • 如果密码正确。服务器端创建Session,通过Cookie把sessionId返回给浏览器

那么,在这种情况下存在问题:

session存储在服务器中,所以服务器重启,session就丢失了,用户刚登录完,就遇到了服务器重启,此时用户就需要重新登录(严重影响心情!)

解决方案:

  1. session存储在一个公用机械(或者缓存等)比如redis(服务端)
  2. 比较常见的就是token(客户端)----》常见!

token是一个带有一定信息的字符串,不能伪造(是客户端进行访问时候携带的)

token不是加密,主要是不能伪造!

那么,此时JWT令牌应运而生!!(当然,处理该问题的不止JWT令牌一个方式!只不过JWT令牌是开源而且免费的,比较适合学生study!)

JSON Web Tokens - jwt.io

JSON Web Tokens - jwt.io

令牌其实就是一个用户的身份标识,名称起的很高大上,其实本质就是一个字符串!

比如我们出行在外,会带自己的身份证,需要验证身份时,就掏出身份证,此时身份证就是一个令牌!身份证不能伪造,可以辨别真假!

当我们使用令牌技术来实现登录的时候:

  1. 根据用户名和密码,验证密码是否正确
  2. 如果密码正确,后端生成token,并返回给前端
  3. 后续访问时,携带token(通常放在Http请求的Header中),后端校验token的合法性

JSON Web Tokens - jwt.io

JWT组成:

JWT由三部分组成,每部分中间使用点(.)分隔,比如aaaa.bbb.ccc

  • Header(头部):头部包括令牌类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA)
  • Payload(负载):负载部分是存放有效信息的地方,里面是一些自定义内容,比如:{"userId":"123","userName":"zhangsan"},也可以存在jwt提供的现场字段,比如exp(过期时间戳)等(此部分不建议存放敏感信息,因为此部分可以解码还原原始内容!)
  • Signature(签名):此部分用于防止jwt内容被篡改,确保安全性!(防止被篡改,而不是防止被解析)

JWT之所以安全,就是因为最后的签名.jwt当中任何⼀个字符被篡改,整个令牌都会校验失败.
就好⽐我们的⾝份证,之所以能标识⼀个⼈的⾝份,是因为他不能被篡改,⽽不是因为内容加密.(任何⼈都可以看到⾝份证的信息,jwt也是)

 用户登录

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/login")
    public Result login(String userName, String password){
        /**
         * 1. 参数校验
         * 2. 密码校验
         * 3. 生成token, 并返回
         */
        if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){
            return Result.fail("用户名或密码为空");
        }
        //获取数据库中的密码
        UserInfo userInfo = userService.queryByName(userName);
        if (userInfo==null || userInfo.getId()<0){
            return Result.fail("用户不存在");
        }
        if (!password.equals(userInfo.getPassword())){
            return Result.fail("账号或密码错误!");
        }
//        if (!SecurityUtils.verify(password, userInfo.getPassword())){
//            return Result.fail("账号或密码错误!");
//        }
        //生成token, 并返回
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userInfo.getId());
        claim.put("name", userInfo.getUserName());
        String token = JwtUtils.genToken(claim);
        return Result.success(token);
    }
    /**
     * 获取登录用户的信息
     */
    @RequestMapping("/getUserInfo")
    public UserInfo getUserInfo(HttpServletRequest request){
        //1. 从token中获取用户ID
        //2. 根据用户ID, 获取用户信息
        String token = request.getHeader("user_token");
        Integer userId = JwtUtils.getUserIdFromToken(token);
        if (userId==null){
            return null;
        }
        return userService.queryById(userId);
    }
   
}

JWT工具类:

/**
 * Jwt工具类
 */
@Slf4j
public class JwtUtils {
    //过期时间: 1小时
    private static final long expiration = 60 * 60 * 1000;
    private static final String secretString = "5CRMLhF7dQnOLCNjJw8dawYK2zTUxS4jDgUW2L99Tdo=";
    private static final Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));

    public static String genToken(Map<String, Object> claim){
        String token = Jwts.builder()
                .setClaims(claim) //设置载荷信息
                .setExpiration(new Date(System.currentTimeMillis()+expiration)) //设置过期时间
                .signWith(key)  //设置签名
                .compact();
        return token;
    }

    public static Claims parseToken(String token){
        if (token==null){
            return null;
        }
        JwtParser build = Jwts.parserBuilder().setSigningKey(key).build();
        Claims claims = null;
        try {
            claims = build.parseClaimsJws(token).getBody();
        }catch (Exception e){
//            e.printStackTrace();
            log.error("解析token失败, token:"+token);
        }
        return claims;
    }

    public static Integer getUserIdFromToken(String token){
        Claims claims = parseToken(token);
        if (claims==null){
            return null;
        }
        return (Integer) claims.get("id");
    }

//    public static void main(String[] args) {
//        String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiemhhbmdzYW4iLCJpZCI6MSwiZXhwIjoxNzA1ODAyNzUyfQ.atKGO-q32Dy5PYfFZZgoogHwbkULivFR_7sXF1Dw-so";
//        Claims claims = parseToken(token);
//        System.out.println(claims);
//    }

}

不完全代码,仅供参考!

相关推荐

  1. <span style='color:red;'>JWT</span><span style='color:red;'>令</span><span style='color:red;'>牌</span>

    JWT

    2024-03-17 09:48:02      20 阅读
  2. <span style='color:red;'>JWT</span><span style='color:red;'>令</span><span style='color:red;'>牌</span>

    JWT

    2024-03-17 09:48:02      16 阅读
  3. JWT

    2024-03-17 09:48:02       9 阅读
  4. SpringBoot登录校验-JWT

    2024-03-17 09:48:02       37 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-17 09:48:02       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-17 09:48:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-17 09:48:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-17 09:48:02       18 阅读

热门阅读

  1. React懒加载

    2024-03-17 09:48:02       21 阅读
  2. awk命令——文本数据格式处理工具

    2024-03-17 09:48:02       22 阅读
  3. 门牌制作-蓝桥杯?-Lua 中文代码解题第3题

    2024-03-17 09:48:02       20 阅读
  4. 飞桨科学计算套件PaddleScience

    2024-03-17 09:48:02       17 阅读
  5. Redis列表:高效消息通信与实时数据处理的利器

    2024-03-17 09:48:02       19 阅读
  6. qt 使用有参数的信号和槽

    2024-03-17 09:48:02       18 阅读
  7. Git 命令大全

    2024-03-17 09:48:02       17 阅读
  8. 小程序的wxss和css区别?

    2024-03-17 09:48:02       20 阅读
  9. Jenkins: 配合docker来部署项目

    2024-03-17 09:48:02       20 阅读