JWT验证用户信息功能与OAuth2协议

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: JWT验证用户信息功能与OAuth2协议

1 简介

JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记。也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据。此特性便于可伸缩性, 同时保证应用程序的安全。


在身份验证过程中, 当用户使用其凭据成功登录时, 将返回 JSON Web token, 并且必须在本地保存 (通常在本地存储中)。


每当用户要访问受保护的路由或资源 (端点) 时, 用户代理(user agent)必须连同请求一起发送 JWT, 通常在授权标头中使用Bearer schema。后端服务器接收到带有 JWT 的请求时, 首先要做的是验证token。

2 格式

  • JWT就是一个字符串,经过加密处理与校验处理的字符串,形式为:A.B.C
  • A由JWT头部信息header经过base64加密得到
    #默认的头信息
    {
      "alg": "HS256",
      "typ": "JWT"
    }
    #官网测试:https://jwt.io/
    #base64加密后的字符串为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  • B是payload,存放有效信息的地方,这些信息包含三个部分:
  • 标准中注册的声明 (建议但不强制使用)
  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
  • 公共的声明
  • 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
  • 私有的声明
  • 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
    #存放的数据:
    {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    }
    #base64后的字符串为:
    eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
  • C由A和B通过加密算法得到,用作对token进行校验,看是否有效
  • 这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
    #secret为:oldlu
    #得到的加密字符串为:DwMTjJktoFFdClHqjJMRgYzICo6FJOUc3Jmev9EScBc
    #整体的token为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.DwMTjJktoFFdClHqjJMRgYzICo6FJOUc3Jmev9EScBc

3 流程

4 示例

导入依赖:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

编写测试用例:

package com.tanhua.sso.service;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class TestJWT {
    String secret = "oldlu";
    @Test
    public void testCreateToken(){
        Map<String, Object> header = new HashMap<String, Object>();
        header.put(JwsHeader.TYPE, JwsHeader.JWT_TYPE);
        header.put(JwsHeader.ALGORITHM, "HS256");
        Map<String, Object> claims = new HashMap<String, Object>();
        claims.put("mobile", "1333333333");
        claims.put("id", "2");
        // 生成token
        String jwt = Jwts.builder()
                .setHeader(header)  //header,可省略
                .setClaims(claims) //payload,存放数据的位置,不能放置敏感数据,如:密码等
                .signWith(SignatureAlgorithm.HS256, secret) //设置加密方法和加密盐
                .setExpiration(new Date(System.currentTimeMillis() + 3000)) //设置过期时间,3秒后过期
                .compact();
        System.out.println(jwt);
    }
    @Test
    public void testDecodeToken(){
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtb2JpbGUiOiIxMzMzMzMzMzMzIiwiaWQiOiIyIiwiZXhwIjoxNjA1NTEzMDA2fQ.1eG3LpudD4XBycUG39UQDaKVBQHgaup-E1OLWo_m8m8";
        try {
            // 通过token解析数据
            Map<String, Object> body = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
            System.out.println(body); //{mobile=1333333333, id=2, exp=1605513392}
        } catch (ExpiredJwtException e) {
            System.out.println("token已经过期!");
        } catch (Exception e) {
            System.out.println("token不合法!");
        }
    }
}

2、校验token

在整个系统架构中,只有SSO保存了JWT中的秘钥,所以只能通过SSO系统提供的接口服务进行对token的校验,所以在SSO系统中,需要对外开放接口,通过token进行查询用户信息,如果返回null说明用户状态已过期或者是非法的token,否则返回User对象数据。

2.1、UserController

    /**
     * 校验token,根据token查询用户数据
     *
     * @param token
     * @return
     */
    @GetMapping("{token}")
    public User queryUserByToken(@PathVariable("token") String token) {
        return this.userService.queryUserByToken(token);
    }

2.2、UserService

  public User queryUserByToken(String token) {
        try {
            // 通过token解析数据
            Map<String, Object> body = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
            User user = new User();
            user.setId(Long.valueOf(body.get("id").toString()));
            //需要返回user对象中的mobile,需要查询数据库获取到mobile数据
            //如果每次都查询数据库,必然会导致性能问题,需要对用户的手机号进行缓存操作
            //数据缓存时,需要设置过期时间,过期时间要与token的时间一致
            //如果用户修改了手机号,需要同步修改redis中的数据
            String redisKey = "TANHUA_USER_MOBILE_" + user.getId();
            if(this.redisTemplate.hasKey(redisKey)){
                String mobile = this.redisTemplate.opsForValue().get(redisKey);
                user.setMobile(mobile);
            }else {
                //查询数据库
                User u = this.userMapper.selectById(user.getId());
                user.setMobile(u.getMobile());
                //将手机号写入到redis中
                //在jwt中的过期时间的单位为:秒
                long timeout = Long.valueOf(body.get("exp").toString()) * 1000 - System.currentTimeMillis();
                this.redisTemplate.opsForValue().set(redisKey, u.getMobile(), timeout, TimeUnit.MILLISECONDS);
            }
            return user;
        } catch (ExpiredJwtException e) {
            log.info("token已经过期! token = " + token);
        } catch (Exception e) {
            log.error("token不合法! token = "+ token, e);
        }
        return null;
    }

2.3、测试

数据已经存储到redis中

2.4、查询好友动态

查询好友动态其实就是查询自己的时间线表,好友在发动态时已经将动态信息写入到了自己的时间线表中。

目录
相关文章
|
30天前
|
JSON JavaScript 数据格式
jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能。
jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能。
44 1
|
6月前
|
JSON 算法 安全
Django JWT验证
Django JWT验证
121 0
|
8月前
|
Java
SpringBoot 整合JWT实现基于自定义注解的-登录请求验证拦截(保姆级教学,附:源码)2
SpringBoot 整合JWT实现基于自定义注解的-登录请求验证拦截
135 0
|
19天前
|
JSON 安全 关系型数据库
SpringCloud Gateway 实现自定义全局过滤器 + JWT权限验证
SpringCloud Gateway 实现自定义全局过滤器 + JWT权限验证
|
1月前
|
JSON 前端开发 Java
|
3月前
|
JavaScript 前端开发 数据库
vue与jwt验证
vue与jwt验证
30 0
|
3月前
|
JSON 算法 前端开发
gin框架JWT验证实践(原理介绍,代码实践)
gin框架JWT验证实践(原理介绍,代码实践)
50 0
|
4月前
|
安全 Java API
深度解析 Spring Security:身份验证、授权、OAuth2 和 JWT 身份验证的完整指南
Spring Security 是一个用于保护基于 Java 的应用程序的框架。它是一个功能强大且高度可定制的身份验证和访问控制框架,可以轻松地集成到各种应用程序中,包括 Web 应用程序和 RESTful Web 服务。 Spring Security 提供了全面的安全解决方案,用于身份验证和授权,并且可以用于在 Web 和方法级别上保护应用程序。
273 0
|
5月前
|
存储 安全 前端开发
深入探讨安全验证:OAuth2.0、Cookie与Session、JWT令牌、SSO与开放授权平台设计
这篇文章讨论了认证和授权的概念,并探讨了设计权限认证框架的原则。它还比较了Cookie和Session的区别,并探讨了处理分布式部署时的Session保存问题。此外,文章还介绍了CSRF攻击及其防范方法,以及OAuth2.0、JWT令牌和SSO的概念。最后,文章提出了设计开放授权平台时需要考虑的因素。
深入探讨安全验证:OAuth2.0、Cookie与Session、JWT令牌、SSO与开放授权平台设计
|
6月前
|
存储 NoSQL Java
SpringBoot自定义实现类似jwt权限验证效果
SpringBoot自定义实现类似jwt权限验证效果
49 0