资讯专栏INFORMATION COLUMN

Java安全验证之JWT实践

Codeing_ls / 760人阅读

摘要:有效载荷的第二部分是有效载荷,其中包含声明。这些是自定义声明,用于在同意使用这些声明的各方之间共享信息,这些信息既没有注册也没有公开声明。由于令牌是凭证,因此必须非常小心以防止出现安全问题。授予授权后,授权服务器会向应用程序返回。

先给出JWT的官方文档

什么是JWT?

JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,用于在各方之间作为JSON对象安全地传输信息。

什么时候应该使用JWT?

授权:这是使用JWT的最常见方式。一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由,服务和资源。Single Sign On是一种现在广泛使用JWT的功能,因为它的开销很小,并且能够在不同的域中轻松使用。

信息交换:JSON Web令牌是在各方之间安全传输信息的好方法。因为JWT可以通过签名(使用公钥/私钥对 )核实发送人的身份。此外,由于使用标头和有效负载计算签名,您还可以验证内容是否未被篡改。

JWT令牌结构

JWT令牌由Header、Payload、Signature三部分组成,每部分之间用点号分隔,通常的形式为xxxxx.yyyyy.zzzzz,下面分别对每部分做详细介绍。

Header(头)

Header通常由两部分组成:令牌的类型,即JWT,以及使用的签名算法,例如HMAC SHA256或RSA。

{
  "alg": "HS256",
  "typ": "JWT"
}

这个JSON被编码为Base64Url,形成JWT的第一部分。

Payload(有效载荷)

JWT的第二部分是有效载荷,其中包含声明( claims)。声明包含实体(通常是用户)和其他自定义信息。声明有三种类型:registered, publicprivate claims

registered claims :这是一组预定义声明,不是强制性的,但建议使用,以提供一组有用的,可互操作的声明。其中包括: iss(发行人), exp(到期时间),sub(主题), aud(受众)。

请注意:声明名称只有三个字符,因为JWT需要保持简洁。

public claims:这些可以由使用JWT的人随意定义。但为避免冲突,应在 IANA JSON Web Token Register中定义它们,或者将其定义为包含防冲突命名空间的URI。

private claims:这些是自定义声明,用于在同意使用这些声明的各方之间共享信息,这些信息既没有注册也没有公开声明。

Payload经过Base64Url编码,形成JWT的第二部分。

请注意:对于JWT令牌,虽然可以防止被篡改,但任何人都可以读取。除非加密,否则不要将秘密信息放在JWT的有效载荷或头元素中。

Signature(签名)

Signature由Base64Url加密的Header、Payload再使用Header中指定的算法加密之后再和secret组成。

如果要使用HMACSHA256算法,将按以下方式创建签名:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

Signature用于验证消息在此过程中未被更改,并且,在使用私钥签名的令牌的情况下,它还可以验证JWT的发件人的身份。

总结

最后将JWT的三部分由点号分隔作为一个字符串,其可以在HTML和HTTP环境中轻松传递,并且比基于XML的标准的Token(如SAML)更加简洁。

JWT工作流程

在身份验证中,当用户使用其凭据成功登录时,将返回JSON Web Token。由于令牌是凭证,因此必须非常小心以防止出现安全问题。一般情况下,您不应该将令牌保留的时间超过要求。

每当用户想要访问受保护的路由或资源时,用户发送JWT到相应的地址,通常在Authorization标头中。请求头的的内容应如下所示:

Authorization: Bearer 

在某些情况下,这可以是无状态授权机制。服务器的受保护路由将检查Authorization标头中的有效JWT ,如果存在,则允许用户访问受保护资源。如果JWT包含必要的数据,则可以减少查询数据库以进行某些操作的需要,尽管可能并非总是如此。

如果在标Authorization头中发送Token,则跨域资源共享(CORS)将不会成为问题,因为它不使用cookie。

下图显示了如何获取JWT并用于访问API或资源:

应用程序或客户端向授权服务器发送授权请求。

授予授权后,授权服务器会向应用程序返回JWT。

应用程序使用JWT来访问受保护资源(如API)。

请注意:使用JWT时,Token中包含的所有信息都会向用户或其他方公开,即使他们无法更改。所以您不应该在令牌中放置秘密信息。

JWT中的JAVA实现

JWT的java实现非常多,详细何以查看官方文档。

其中常用的有com.auth0.java-jwt和io.jsonwebtoken.jjwt

这里我采用 jjwt 作为演示,因为他的Github中的Star比较多。

Maven依赖

    io.jsonwebtoken
    jjwt-api
    0.10.5


    io.jsonwebtoken
    jjwt-impl
    0.10.5
    runtime


    io.jsonwebtoken
    jjwt-jackson
    0.10.5
    runtime

创建Token
    //Sample method to construct a JWT
    public static String createJWT(String id, String issuer, String subject, long ttlMillis) {

        //The JWT signature algorithm we will be using to sign the token
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        //We will sign our JWT with our ApiKey secret
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary( APP_ID + APP_SECRET);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        //Let"s set the JWT Claims
        JwtBuilder builder = Jwts.builder().setId(id)
                .setIssuedAt(now)
                .setSubject(subject)
                .setIssuer(issuer)
                .signWith(signatureAlgorithm, signingKey);

        //if it has been specified, let"s add the expiration
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }

        //Builds the JWT and serializes it to a compact, URL-safe string
        return builder.compact();

    }
解析Token
     //Sample method to validate and read the JWT
    public static Claims parseJWT(String jwt) {

        //This line will throw an exception if it is not a signed JWS (as expected)
        Claims claims = Jwts.parser()
                .setSigningKey(DatatypeConverter.parseBase64Binary(APP_ID + APP_SECRET))
                .parseClaimsJws(jwt).getBody();
//        System.out.println("ID: " + claims.getId());
//        System.out.println("Subject: " + claims.getSubject());
//        System.out.println("Issuer: " + claims.getIssuer());
//        System.out.println("Expiration: " + claims.getExpiration());
        return claims;
    }

其中APP_IDAPP_SECRET可以自定义为你想要的任何值,但是不能过于简单。

你会发现我们再使用的时候没有设置Header的值,因为jjwt为了我们使用方便会根据使用的签名算法或压缩算法自动设置它们。

使用
@Test
public void createJWT(){

    String jwt = JWTUtil.createJWT("1", "111", "admin", JWTUtil.DAY_TTL);
    System.out.println(jwt);
}

@Test
public void parseJWT(){
            Claims claims = JWTUtil.parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxIiwiaWF0IjoxNTQ4Mjk1NjQ0LCJzdWIiOiJhZG1pbiIsImlzcyI6IjExMSIsImV4cCI6MTU0ODMzODg0NH0.WRkyeG3MfVor02Ya4732fgGydXhtkkKSDwbxOIZ2i9Y");
    System.out.println(claims);
}

如果想使用jjwt更复杂的功能或者其他的Java实现可以去他们相应的Github上学习。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73195.html

相关文章

  • Spring Security

    摘要:框架具有轻便,开源的优点,所以本译见构建用户管理微服务五使用令牌和来实现身份验证往期译见系列文章在账号分享中持续连载,敬请查看在往期译见系列的文章中,我们已经建立了业务逻辑数据访问层和前端控制器但是忽略了对身份进行验证。 重拾后端之Spring Boot(四):使用JWT和Spring Security保护REST API 重拾后端之Spring Boot(一):REST API的搭建...

    keelii 评论0 收藏0
  • 论微服务安全

    摘要:微服务能够为应用程序设计提供一种更具针对性范围性与模块性的实现方案。安全微服务部署模式可谓多种多样但其中使用最为广泛的当数每主机服务模式。在微服务环境下,安全性往往成为最大的挑战。不同微服务之间可通过多种方式建立受信关系。 每个人都在讨论微服务,每个人也都希望能够实现微服务架构,而微服务安全也日渐成为大家关注的重要问题。今天小数与大家分享的文章,就从应用层面深入探讨了应对微服务安全挑战...

    plokmju88 评论0 收藏0
  • Java经典

    摘要:请注意,我们在聊聊单元测试遇到问题多思考多查阅多验证,方能有所得,再勤快点乐于分享,才能写出好文章。单元测试是指对软件中的最小可测试单元进行检查和验证。 JAVA容器-自问自答学HashMap 这次我和大家一起学习HashMap,HashMap我们在工作中经常会使用,而且面试中也很频繁会问到,因为它里面蕴含着很多知识点,可以很好的考察个人基础。但一个这么重要的东西,我为什么没有在一开始...

    xcold 评论0 收藏0
  • 理解JWT(JSON Web Token)认证及python实践

    摘要:认证服务器,即服务提供商专门用来处理认证的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。客户端使用上一步获得的授权,向认证服务器申请令牌。认证服务器对客户端进行认证以后,确认无误,同意发放令牌。 最近想做个小程序,需要用到授权认证流程。以前项目都是用的 OAuth2 认证,但是Sanic 使用OAuth2 不太方便,就想试一下 JWT 的认证方式。这一篇主要内容是 ...

    BigTomato 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<