分布式认证JWT

JWT解释

JWT是一种加密后的数据载体,可在各应用间进行数据传输。

JWT的组成

包含3部分。header(头)、payload(有效载荷)、signature(签名)。格式是header.payload.signature

Header组成

JWT的头部承载两部分信息

声明类型,默认是JWT

声明加密的算法 常用的算法:HMAC、RSA、ECDSA等

bash 复制代码
{
	"alg":"HS256"
	"typ":"JWT"
}

alg:表示签名的算法,默认是 HMAC SHA256(写成 HS256);

typ:表示令牌(token)的类型,JWT 令牌统一写为 JwT。使用Base64加密,构成了JT第一部分-header

Payload组成

Payload 部分也是一个JSON 对象,用来存放实际需要传递的有效信息。

标准载荷:有很多,建议使用,但不强制,对T信息作补充。

标准载荷 介绍
iss (issuer) 签发人(谁签发的)
exp (expiration time) 过期时间,必须要大于签发时间
sub (subject) 主题(用来做什么)
aud (audience) 受众(给谁用的)比如:http://www.xxx.com
nbf (Not Before) 生效时间
iat (lssued At) 签发时间
jti (JWT ID) 编号,JWT的唯一身份标识

自定义载荷:可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息,因为该部分在客户端可解密。

bash 复制代码
{
	#自定义载荷
	"user_info":[
		{"id": "1"},
		{"name": "lili"},
		{"age": "18"}
	]
	#标准载荷
	"iat": 1681571257.
	"exp":1682783999
	"aud":"xiaofei",
	"iss":"dafei"
	"sub": "alluser'
}

使用Base64加密,构成了JT第二部分payload

signature组成

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

java 复制代码
signature =HMACSHA256(base64urlEncode(header)+""+ base64UrlEncode(payload),secret)

算出签名以后,把 Header、Pavload、signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

因为有这个密钥的存在,所以即便调用方偷偷的修改了前两部分的内容,在验证环节就会出现签名不一致的情况,所以保证了安全性。

使用Base64加密,构成了JT第三部分-signature

实践

xml 复制代码
 <dependencies>
            <!--JWT(Json Web Token)登录支持-->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt-api</artifactId>
                <version>0.11.5</version>
            </dependency>
            <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>
                <version>0.11.5</version>
                <scope>runtime</scope>
            </dependency>
        </dependencies>
java 复制代码
public class JwtUtil {
    static String USER_INFO_USERNAME = "username";
    static int JWT_EXPIRATION = 24 * 60 * 60 * 1000;
    static String JWT_SECRET = "jwtsecretfdghfghfdfgdfgdfsgdfgdfgfdgdfgdfgdfgdfg";
    static String JWT_CREATE_TIME = "jwtCreateTime";
    static String USER_INFO_ID = "id";

    public static String createToken(Map<String, Object> claims) {
        String token = Jwts.builder()
//                .setHeader(new HashMap<>())
                .setAudience("Audience")
                .setIssuer("Issuer")
                .setSubject("Subject")
                .setNotBefore(new Date())
                .setIssuedAt(new Date())
                .setId("jwt id")
                .setClaims(claims)//载荷
                .setExpiration(generateExpirationDate())
                .signWith(Keys.hmacShaKeyFor(Decoders.BASE64.decode(JWT_SECRET)))
                .compact();
        return token;
    }

    private static Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + JWT_EXPIRATION);
    }

    public static Claims parseToken(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(Decoders.BASE64.decode(JWT_SECRET))
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims;
    }

    public static String getUsername(String token) {
        Claims claims = parseToken(token);
        return getValue(claims, USER_INFO_USERNAME);
    }

    public static boolean validateToken(String token) {
        Claims claims = parseToken(token);
        return claims != null && !isTokenExpired(token);
    }

    private static boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDate(token);
        return expiredDate.before(new Date());
    }

    private static Date getExpiredDate(String token) {
        Claims claims = parseToken(token);
        return claims.getExpiration();
    }

    private static String refreshToken(String token) {
        Claims claims = parseToken(token);
        claims.put(JWT_CREATE_TIME, new Date());
        return createToken(claims);
    }

    private static String getValue(Claims claims, String key) {
        return claims.get(key) != null ? claims.get(key).toString() : null;
    }
}
java 复制代码
@RestController
public class UserController {

    private static Map<String, User> map = new HashMap();

    @GetMapping("/register")
    public String register(User user) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(USER_INFO_ID, user.getId());
        claims.put(USER_INFO_USERNAME, user.getUsername());
        claims.put(JWT_CREATE_TIME, new Date());
        String token = JwtUtil.createToken(claims);
        map.put(token, user);
        return "/active?jwt= " + token;
    }

    public void active(String jwt) {
        User user = map.get(jwt);
        if (user != null && JwtUtil.validateToken(jwt)) {
            map.remove(jwt);
            System.out.println("active");
        } else {
            System.out.println("param 不合法 ");
        }
    }
}
相关推荐
鸽鸽程序猿6 小时前
【JavaEE】【SpringCloud】分布式事务 Alibaba Seata
分布式·spring cloud·java-ee
没有bug.的程序员7 小时前
Spring Cloud Sentinel:熔断降级规则配置与分布式流量防线实战终极指南
java·分布式·后端·spring cloud·sentinel·熔断规则·分布式流量防线
梵得儿SHI7 小时前
实战项目落地:微服务拆分原则(DDD 思想落地,用户 / 订单 / 商品 / 支付服务拆分实战)
spring cloud·微服务·云原生·架构·微服务拆分·ddd方法论·分布式数据一致性
努力也学不会java7 小时前
【Spring Cloud】优雅实现远程调用-OpenFeign
java·人工智能·后端·spring·spring cloud
m0_740043732 天前
【无标题】
java·spring boot·spring·spring cloud·微服务
编程彩机2 天前
互联网大厂Java面试:从微服务到分布式缓存的技术场景解析
redis·spring cloud·消息队列·微服务架构·openfeign·java面试·分布式缓存
Anastasiozzzz2 天前
Nginx和Ribbon的区别
后端·spring cloud·ribbon
码农水水2 天前
从 OpenFeign 到 RestClient:Spring Cloud 新时代的轻量化 HTTP 调用方案
java·运维·后端·spring·http·spring cloud·面试
what丶k3 天前
SpringBoot3 配置文件使用全解析:从基础到实战,解锁灵活配置新姿势
java·数据库·spring boot·spring·spring cloud
小信丶3 天前
@Activate 注解详解:应用场景与实战示例
java·spring boot·后端·spring·spring cloud·微服务·dubbo