服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - 编程技术 - JWT在身份验证与信息交换中的实践探索

JWT在身份验证与信息交换中的实践探索

2024-04-01 15:03沐雨花飞蝶 编程技术

JWT是指JSON Web Token,一种用于在网络上安全传输信息的开放标准(RFC 7519),定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。JWT由三部分组成,分别是头部(Header)、载荷(Payload)和签名(Signatu

JWT

JWT是指JSON Web Token,一种用于在网络上安全传输信息的开放标准(RFC 7519),定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。JWT由三部分组成,分别是头部(Header)、载荷(Payload)和签名(Signature)。通常被用来在用户和服务器之间传递身份信息,以及在不同的系统之间安全地传递声明。JWT通常被用于身份验证和信息交换,特别是在前后端分离的应用中。

JWT工作示意图:JWT在身份验证与信息交换中的实践探索

  1. 用户登录后,服务端会将用户的识别信息进行加密生成一个有有效期的token返回给用户端。
  2. 用户端收到token后将其进行保存,并在以后的每一次请求时将该token带上发送给服务器。
  3. 服务器接收到用户的token后,进行验证用户的身份、权限、有效期等信息,验证通过即放行,验证不通过就拒绝服务。

JWT由三部分组成,分别是头部(header)、载荷(payload)和签名(signature)。

  1. 头部(header):包含了令牌的类型(即JWT)和所使用的签名算法(例如HMAC SHA256或RSA)。
  2. 载荷(payload):包含了要传递的信息,以及一些标准的声明和自定义的声明。标准的声明包括令牌的过期时间(exp)、发布时间(iat)等。自定义的声明可以根据需要添加。
  3. 签名(signature):使用头部指定的算法和密钥对头部和载荷进行签名,以确保令牌在传输过程中没有被篡改。

JWT的三部分使用点号(.)连接起来,形成一个完整的JWT令牌。例如:xxxxx.yyyyy.zzzzz

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJaSEFOR1hVTiIsImJvZHkiOnsidXNlclJvbGUiOiJhZG1pbiIsInVzZXJpZCI6IjAwMSJ9LCJleHAiOjE2NjI5NTIxNjIsImlhdCI6MTY2Mjk1MTU1NywianRpIjoiZGZhN2MyZjUtNGNjMC00OWFhLWFiMDUtYzZhY2M4M2YxMDViIn0.xOleM21i7-EI0oOq83Xm-nQVOufajHCupY2QjkpwreQ

JWT通常用于身份验证和授权,因为它们可以包含用户的信息,并且可以被验证和信任。通常用于API认证,因为可以在多个系统之间安全地传递信息,而无需使用cookie或session。

JWT使用

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>4.4.0</version>
</dependency>
@Slf4j
@RestController
public class TokenController {
    @Autowired
    private TokenUtil tokenUtil;

    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password){
        if(!"admin".equals(username) || !"123".equals(password)){
            log.info("账号或者密码错误!");
        }

        // 模拟从数据库中获取的用户识别信息
        String userId = "001";
        String userRole = "admin";
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("userId", userId);
        dataMap.put("userRole", userRole);

        // 将用户识别信息存储到token中
        String token = tokenUtil.createToken(dataMap);
        log.info("生成的token为:{}", token);
        return token;
    }

    @PostMapping("/getUserInfo")
    public String getUserInfo(@RequestParam String token){
        if(ObjectUtils.isEmpty(token)){
            log.info("token不能为空!");
            return "token不能为空!";
        }

        log.info("收到的token为:{}", token);
        Map<String, Object> dataMap = tokenUtil.parseToken(token);
        String userRole = dataMap.get("userRole").toString();
        if(!"admin".equals(userRole)){
            log.info("非管理员角色,不允许访问!");
            return "非管理员角色,不允许访问!";
        }

        String userId = dataMap.get("userId").toString();
        return "允许登录,用户为:" + userId;
    }
}
@Component
public class TokenUtil {

    private static final String DEFAULT_SECRET = "666";

    private static final String DEFAULT_DATA_KEY = "body";

    private static final String DEFAULT_ISSUER = "REATHIN";

    private static final Long DEFAULT_EXPIRE_TIME = 7*24*60*60L;


    public String createToken(Map<String, Object> dataMap){
        return createToken(dataMap, DEFAULT_SECRET);
    }

    public String createToken(Map<String, Object> dataMap, String secret){
        // 指定使用的加密算法
        Algorithm algorithm = Algorithm.HMAC256(secret);
        return JWT.create()
                .withClaim(DEFAULT_DATA_KEY, dataMap)
                .withIssuer(DEFAULT_ISSUER)
                .withIssuedAt(new Date())
                .withExpiresAt(new Date(System.currentTimeMillis() + DEFAULT_EXPIRE_TIME * 1000))
                .withJWTId(UUID.randomUUID().toString())
                .sign(algorithm);
    }

    public Map<String, Object> parseToken(String token){
        return parseToken(token, DEFAULT_SECRET);
    }

    public Map<String, Object> parseToken(String token, String secret){
        // 指定使用的加密算法
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        return decodedJWT.getClaim(DEFAULT_DATA_KEY).asMap();
    }

}

JWT优缺点

优点:

  1. 无状态性(Stateless):JWT包含了所有用户的必要信息,服务器不需要存储用户的会话信息,因此可以轻松地扩展应用程序。
  2. 跨域支持(Cross-Origin Support):JWT可以在跨域场景下使用,因为它可以通过HTTP头部进行传递。
  3. 安全性(Security):JWT可以使用签名和加密来验证发送方的身份和确保数据的完整性。
  4. 灵活性(Flexibility):JWT可以用于各种场景,包括身份验证和信息交换。

缺点:

  1. 无法撤销(Non-Revocable):一旦JWT被签发,就无法撤销,除非设置短期过期时间。
  2. 增加网络负担(Increased Network Overhead):由于JWT包含了用户信息,因此会增加网络传输的负担。
  3. 潜在安全风险(Potential Security Risks):如果JWT被盗取,攻击者可以获得用户的所有信息,因此需要谨慎存储和传输JWT。
  4. 不适合存储敏感信息(Not Suitable for Storing Sensitive Information):由于JWT可以被解码,因此不适合存储敏感信息,如密码等。

原文地址:https://mp.weixin.qq.com/s/gk3XVF4rPrMMVay6kYii_w

延伸 · 阅读

精彩推荐
  • 编程技术Git 教程之基本操作详解

    Git 教程之基本操作详解

    本文主要主要介绍Git 基本操作,这里整理了详细的基本操作资料,包括基本命令使用方法,有需要的朋友可以参考下 ...

    菜鸟教程3792020-08-02
  • 编程技术程序员也需了解的主流云计算网络架构

    程序员也需了解的主流云计算网络架构

    当前越来越多的企业将自己的业务迁移至云端,云计算的发展势头不可阻挡,身边好多朋友也纷纷购买云主机用来学习测试。有那么一波小伙伴们肯定好奇...

    今日头条3212020-11-10
  • 编程技术浅谈服务发现和负载均衡的来龙去脉

    浅谈服务发现和负载均衡的来龙去脉

    单机时代,传统软件大多是单体/巨石架构(Monolithic)。大家往一个代码仓库提交CODE,这会导致应用膨胀,以及扩展受限,无法按需伸缩等诸多问题。单体架...

    华为云开发者社区7182022-09-05
  • 编程技术Amazing!CSS 也能实现烟雾效果?

    Amazing!CSS 也能实现烟雾效果?

    最近利用 CSS 实现了一些看似超出 CSS 能力的效果,本文继续此系列,本文主要想探讨一下,使用 CSS 能否比较好的实现一些烟雾效果。...

    iCSS前端趣闻6562021-12-27
  • 编程技术关于软件架构的一切

    关于软件架构的一切

    软件开发可以描述为一个复杂的系统过程,需要在各个技术领域以及相关业务方面的专业知识。就像总体规划的蓝图一样,通过定义软件的体系结构,可以...

    今日头条10112021-02-28
  • 编程技术关于配置 Terraform 的五条建议

    关于配置 Terraform 的五条建议

    使用 Terraform 五年的经历让我吸取到一些重要经验。无论团队大小、项目性质,有五条要点对于配置合乎逻辑且可用的 Terraform 平台至关重要。...

    Linux中国8852022-11-03
  • 编程技术vscode代码格式化和eslint的使用

    vscode代码格式化和eslint的使用

    这篇文章主要介绍了vscode代码格式化和eslint的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    吴玉宏5582020-07-07
  • 编程技术键盘扫描码[比较完整]

    键盘扫描码[比较完整]

    键盘扫描码(英语:scancode或scan code)是绝大多数计算机键盘向计算机发送的一项数据,用以报告哪些键被按下。它使用一个数字或数字序列来表示分配到...

    互联网2872020-07-14