栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java实现JWT

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java实现JWT

JWT(JSON Web Token)

        JWT在web环境中通常作为一种用户凭证,它是一个以.分隔,由heaer.payload.signature组成的字符串,其中每个部分都经过base64编码。header包含token采用的算法、类型(JWT)、KeyId等信息,payload中包含token的发行人iss、过期时间exp、业务信息等(比如用户ID、昵称等),signature是对(header.payload)的base64组合串用密钥加密得到的摘要,代表header.payload的签名结果。

JWT生成/验证流程

       生成:对header、payload分别进行base64编码,得到两个base64串,以.拼接这两个串,将该串通过MD5/SHA/MAC等算法生成签名信息得到signature。再以.拼接header.payload.signature,得到token    
       验证:以.为分隔符拆分token串,得到三个子部分,将header.payload采用相同的算法生成新的签名,对比签名来判断token是否被修改、如果有设置过期时间,则进行过期检测(最终通常会从payload中提取信息存储到一个ThreadLocal对象中)。 (注意由于这些摘要算法是不可逆的,所以signature是不能解密的)

JWT代码实现

         实际开发中你可以自己实现,也可以采用第三方库,但通常都会采用Mac算法(Message Authentication Codes消息认证码算法), Mac兼容了MD5及SHA的特性,并且添加了密钥(这里也可称为盐值),能更好的降低碰撞机率,防止暴力破解。

         这里两份代码都贴一下,自己写的话,可以参考下面这份比较粗糙的代码,主要是为了说明流程。第三方库的底层实现流程也类似,通常也是采用javax.crypto.mac算法

package com.ikea.ifood.order.controller;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Objects;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.base64;

import com.auth0.jwt.exceptions.SignatureGenerationException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JWTDemo {
	
	// 密钥(或者叫盐值)
	private String saltSecret = "saltSecret";
	
	// 算法
	private String algorithm = "HmacSHA256";
	
	public String sign(Map headerMap,Map payloadMap) throws SignatureGenerationException, JsonProcessingException, InvalidKeyException, NoSuchAlgorithmException {
		// 0、得到header.payload的base64串
		ObjectMapper objMapper = new ObjectMapper();
		String headerJson = objMapper.writevalueAsString(headerMap);
		String payloadJson = objMapper.writevalueAsString(payloadMap);
        String headerB64 = base64.encodebase64URLSafeString(headerJson.getBytes(StandardCharsets.UTF_8));
        String payloadB64 = base64.encodebase64URLSafeString(payloadJson.getBytes(StandardCharsets.UTF_8));
        String content = String.format("%s.%s", headerB64, payloadB64);
        // 1、生成摘要信息
        byte[] signatureBytes = createSignature(algorithm,saltSecret.getBytes(StandardCharsets.UTF_8),content.getBytes(StandardCharsets.UTF_8));
        String signature = base64.encodebase64URLSafeString((signatureBytes));
        return String.format("%s.%s", content, signature);
    }
	
	private byte[] createSignature(String algorithm, byte[] secretBytes, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException {
        final Mac mac = Mac.getInstance(algorithm);
        mac.init(new SecretKeySpec(secretBytes, algorithm));
        return mac.doFinal(contentBytes);
    }
	
	@SuppressWarnings("unchecked")
	public void verifySignature(String token) throws InvalidKeyException, NoSuchAlgorithmException, JsonMappingException, JsonProcessingException {
		// 0、解析token,得到header.payload的base64串
		String[] parts = token.split("\.");
		String headerB64 = parts[0];
        String payloadB64 = parts[1];
        String signatureB64 = parts[2];
        byte[] contentBytes = String.format("%s.%s", headerB64, payloadB64).getBytes(StandardCharsets.UTF_8);
        
        // 1、生成摘要,进行摘要对比
        byte[] signatureBytes = base64.decodebase64(signatureB64);
        boolean validResult = this.verifySignature(algorithm, saltSecret.getBytes(StandardCharsets.UTF_8), contentBytes, signatureBytes);
        if(!validResult) {
        	// ...验签失败
        }
        // 2、过期判断
        ObjectMapper objMapper = new ObjectMapper();
        String payloadJson = new String(base64.decodebase64(payloadB64),StandardCharsets.UTF_8);
        Map payloadMap = objMapper.readValue(payloadJson, Map.class);
        if(Objects.nonNull(payloadMap.get("exp"))){
        	long endTime = Long.parseLong(String.valueOf(payloadMap.get("exp")));
        	long currSecond = System.currentTimeMillis()/1000;
        	if(currSecond > endTime) {
        		// ...超时异常
        	}
        }
	}
    
    private boolean verifySignature(String algorithm, byte[] secretBytes, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException {
    	// 生成新的签名,对比签名
    	return MessageDigest.isEqual(createSignature(algorithm, secretBytes, contentBytes), signatureBytes);
    }
}

    关于第三方库可以使用,可以使用Java中比较推荐的JJWT(java-jwt)    

//gradle引入
implementation 'com.auth0:java-jwt:3.4.0'  

// maven引入

		com.auth0
		java-jwt
		3.4.0
public class JWTMaker {
	
	@Value("${xxxxx}")
    private String tokenSalt;
    
    private final String ISSUER_NAME = "xxxx";
    
    private final Integer JWT_EXPIRE_TIME = 8;
    
    public String sign(UserInfo user) {
        String token = null;
        try {
            Date expireAt = Date.from(LocalDateTime.now().plusHours(JWT_EXPIRE_TIME).atZone(ZoneId.systemDefault()).toInstant());
            token = JWT.create()
                    .withIssuer(ISSUER_NAME)
                    .withClaim("userId", user.getUserId())
                    .withClaim("name", user.getName())
                    .withExpiresAt(expireAt)
                    .sign(Algorithm.HMAC256(tokenSalt));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return token;
    }

    
    public boolean verify(String token) {
        try {
        	// 0、验签
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenSalt)).withIssuer(ISSUER_NAME).build();
            DecodedJWT jwt = verifier.verify(token);
            
            // 1、提取信息
            UserInfo user = new UserInfo();
            user.setUserId(jwt.getClaim("userId").asString());
            user.setName(jwt.getClaim("name").asString());
            
            // 2、放入到ThreadLocal中,与当前线程绑定。
            // ...
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/341167.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号