精华内容
下载资源
问答
  • Java实现JWT

    2021-02-03 18:12:50
    JWT(JSON Web Token) JWT在web环境中通常作为一种用户凭证,它是一个以.分隔,由heaer.payload.signature组成的字符串,其中每个部分都经过Base64编码。header包含token采用的算法、类型(JWT)、KeyId等信息,...

    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<String,Object> headerMap,Map<String,Object> 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<String,Object> 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引入
    <dependency>
    		<groupId>com.auth0</groupId>
    		<artifactId>java-jwt</artifactId>
    		<version>3.4.0</version>
    </dependency>
    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;
        }
    
        /**
         * 签名验证
         * @param token
         * @return
         */
        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;
            }
        }
    
    }

    展开全文
  • Java实现jwt生成Token

    2021-03-09 00:27:24
    需要使用到的两个jar包//jwtcom.nimbusdsnimbus-jose-jwt4.13.1//redisredis.clientsjedis2.1.0Jwt生成工具类/*** 生成Token工具类**/public class JwtToken {/*** 秘钥*/private static final byte[] SECRET="3d...

    需要使用到的两个jar包

    //jwt

    com.nimbusds

    nimbus-jose-jwt

    4.13.1

    //redis

    redis.clients

    jedis

    2.1.0

    Jwt生成工具类

    /**

    * 生成Token工具类

    *

    */

    public class JwtToken {

    /**

    * 秘钥

    */

    private static final byte[] SECRET="3d990d2276917dfac04467df11fff26d".getBytes();

    /**

    * 初始化head部分的数据为

    * {

    * "alg":"HS256",

    * "type":"JWT"

    * }

    */

    private static final JWSHeader header=new JWSHeader(JWSAlgorithm.HS256, JOSEObjectType.JWT, null, null, null, null, null, null, null, null, null, null, null);

    /**

    * 生成token,该方法只在用户登录成功后调用

    *

    * @param Map集合,可以存储用户id,token生成时间,token过期时间等自定义字段

    * @return token字符串,若失败则返回null

    */

    public static String createToken(Map payload) {

    String tokenString=null;

    // 创建一个 JWS object

    JWSObject jwsObject = new JWSObject(header, new Payload(new JSONObject(payload)));

    try {

    // 将jwsObject 进行HMAC签名

    jwsObject.sign(new MACSigner(SECRET));

    tokenString=jwsObject.serialize();

    } catch (JOSEException e) {

    System.err.println("签名失败:" + e.getMessage());

    e.printStackTrace();

    }

    return tokenString;

    }

    /**

    * 校验token是否合法,返回Map集合,集合中主要包含 state状态码 data鉴权成功后从token中提取的数据

    * 该方法在过滤器中调用,每次请求API时都校验

    * @param token

    * @return Map

    */

    public static Map validToken(String token) {

    Map resultMap = new HashMap();

    try {

    JWSObject jwsObject = JWSObject.parse(token);

    Payload payload = jwsObject.getPayload();

    JWSVerifier verifier = new MACVerifier(SECRET);

    if (jwsObject.verify(verifier)) {

    JSONObject jsonOBj = payload.toJSONObject();

    resultMap.put("state", TokenState.VALID.toString());

    if (jsonOBj.containsKey("ext")) {

    long extTime = Long.valueOf(jsonOBj.get("ext").toString());

    long curTime = new Date().getTime();

    if (curTime > extTime) {

    resultMap.clear();

    resultMap.put("state", TokenState.EXPIRED.toString());

    }

    }

    resultMap.put("data", jsonOBj);

    } else {

    // 校验失败

    resultMap.put("state", TokenState.INVALID.toString());

    }

    } catch (Exception e) {

    //e.printStackTrace();

    // token格式不合法导致的异常

    resultMap.clear();

    resultMap.put("state", TokenState.INVALID.toString());

    }

    return resultMap;

    }

    }

    //检验token状态类

    /**

    * 枚举,定义token的三种状态

    *

    */

    public enum TokenState {

    /**

    * 过期

    */

    EXPIRED("EXPIRED"),

    /**

    * 无效(token不合法)

    */

    INVALID("INVALID"),

    /**

    * 有效的

    */

    VALID("VALID");

    private String state;

    private TokenState(String state) {

    this.state = state;

    }

    /**

    * 根据状态字符串获取token状态枚举对象

    * @param tokenState

    * @return

    */

    public static TokenState getTokenState(String tokenState){

    TokenState[] states=TokenState.values();

    TokenState ts=null;

    for (TokenState state : states) {

    if(state.toString().equals(tokenState)){

    ts=state;

    break;

    }

    }

    return ts;

    }

    public String toString() {

    return this.state;

    }

    public String getState() {

    return state;

    }

    public void setState(String state) {

    this.state = state;

    }

    }

    展开全文
  • 介绍原理在上篇《JWT(一):认识 JSON Web Token》已经说过了,实现起来并不难,你可以自己写一个 jwt 工具类(如果你有兴趣的话)当然了,重复造轮子不是程序员的风格,我们主张拿来主义!JWT 官网提供了多种语言的 ...

    介绍

    原理在上篇《JWT(一):认识 JSON Web Token》已经说过了,实现起来并不难,你可以自己写一个 jwt 工具类(如果你有兴趣的话)

    当然了,重复造轮子不是程序员的风格,我们主张拿来主义!

    3a5a3afcb355e89693c6a063fd4fe9a3.png

    JWT 官网提供了多种语言的 JWT 库,详情可以参考 https://jwt.io/#debugger 页面下半部分

    jjwt 版本 0.10.7,它和 0.9.x 有很大的区别,一定要注意!!!

    本文分5部分

    第1部分:以简单例子演示生成、验证、解析 jwt 过程

    第2部分:介绍 jjwt 的常用方法

    第3部分:封装一个常用的 jwt 工具类

    如果只是拿来主义,看到这里就可以了

    第4部分:介绍 jjwt 的各种签名算法

    第5部分:对 jwt 进行安全加密

    简单例子

    引入 MAVN 依赖

    io.jsonwebtoken

    jjwt-api

    0.10.7

    io.jsonwebtoken

    jjwt-impl

    0.10.7

    runtime

    io.jsonwebtoken

    jjwt-jackson

    0.10.7

    runtime

    一个例子

    // 生成密钥

    String key = "0123456789_0123456789_0123456789";

    SecretKey secretKey = new SecretKeySpec(key.getBytes(), SignatureAlgorithm.HS256.getJcaName());

    // 1. 生成 token

    String token = Jwts.builder() // 创建 JWT 对象

    .setSubject("JSON Web Token") // 设置主题(声明信息)

    .signWith(secretKey) // 设置安全密钥(生成签名所需的密钥和算法)

    .compact(); // 生成token(1.编码 Header 和 Payload 2.生成签名 3.拼接字符串)

    System.out.println(token);

    //token = token + "s";

    // 2. 验证token,如果验证token失败则会抛出异常

    try {

    Jwts.parser()

    .setSigningKey(secretKey)

    .parseClaimsJws(token);

    // OK, we can trust this token

    System.out.println("验证成功");

    } catch (JwtException e) {

    //don't trust the token!

    System.out.println("验证失败");

    }

    // 3. 解析token

    Claims body = Jwts.parser() // 创建解析对象

    .setSigningKey(secretKey) // 设置安全密钥(生成签名所需的密钥和算法)

    .parseClaimsJws(token) // 解析token

    .getBody(); // 获取 payload 部分内容

    System.out.println(body);

    输出结果:

    eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKU09OIFdlYiBUb2tlbiJ9.QwmY_0qXW4BhAHcDpxz62v3xqkFYbg5lsZQhM2t-kVs

    验证成功

    {sub=JSON Web Token}

    常用方法

    以下内容建议参考源码获知更多详情

    Jwts.builder() 创建了 DefaultJwtBuilder 对象,该对象的常用方法如下:

    Header

    在 compact() 方法中会自动根据签名算法设置头部信息,当然也可以手动设置

    setHeader(Header header): JwtBuilder

    setHeader(Map header): JwtBuilder

    setHeaderParams(Map params): JwtBuilder

    setHeaderParam(String name, Object value): JwtBuilder

    参数 Header 对象 可通过 Jwts.header(); 创建,它简单得就像一个 map (把它当做 map 使用即可)

    Payload

    至少设置一个 claims,否则在生成签名时会抛出异常

    setClaims(Claims claims): JwtBuilder

    setClaims(Map claims): JwtBuilder

    addClaims(Map claims): JwtBuilder

    setIssuer(String iss): JwtBuilder

    setSubject(String sub): JwtBuilder

    setAudience(String aud): JwtBuilder

    setExpiration(Date exp): JwtBuilder

    setNotBefore(Date nbf): JwtBuilder

    setIssuedAt(Date iat): JwtBuilder

    setId(String jti): JwtBuilder

    claim(String name, Object value: JwtBuilder

    参数对象 Claims 同 Header 类似,通过 Jwts.claims() 创建,同样简单得就像一个 map

    值得注意的一点是:不要在 setXxx 之后调用 setClaims(Claims claims) 或 setClaims(Map claims),因为这两个方法会覆盖所有已设置的 claim

    Signature

    signWith(Key key)

    signWith(Key key, SignatureAlgorithm alg)

    signWith(SignatureAlgorithm alg, byte[] secretKeyBytes)

    signWith(SignatureAlgorithm alg, String base64EncodedSecretKey)

    signWith(SignatureAlgorithm alg, Key key)

    以上方法最终就是设置两个对象:key 和 algorithm,分别代表密钥和算法

    方法内部生成密钥使用的方法的和演示中的一样

    SecretKey key = new SecretKeySpec(secretKeyBytes, alg.getJcaName());

    注意:key 的长度必须符合签名算法的要求(避免生成弱密钥)

    HS256:bit 长度要>=256,即字节长度>=32

    HS384:bit 长度要>=384,即字节长度>=48

    HS512:bit 长度要>=512,即字节长度>=64

    在 secret key algorithms 名称中的数字代表了最小bit长度

    更多签名算法的详情,请参考签名算法小节

    封装 JWT 工具类

    package com.liuchuanv.jwt;

    import io.jsonwebtoken.*;

    import io.jsonwebtoken.security.SignatureException;

    import javax.crypto.spec.SecretKeySpec;

    import java.security.Key;

    import java.util.Date;

    import java.util.Map;

    import java.util.UUID;

    /**

    * JSON Web Token 工具类

    *

    * @author LiuChuanWei

    * @date 2019-12-11

    */

    public class JwtUtils {

    /**

    * key(按照签名算法的字节长度设置key)

    */

    private final static String SECRET_KEY = "0123456789_0123456789_0123456789";

    /**

    * 过期时间(毫秒单位)

    */

    private final static long TOKEN_EXPIRE_MILLIS = 1000 * 60 * 60;

    /**

    * 创建token

    * @param claimMap

    * @return

    */

    public static String createToken(Map claimMap) {

    long currentTimeMillis = System.currentTimeMillis();

    return Jwts.builder()

    .setId(UUID.randomUUID().toString())

    .setIssuedAt(new Date(currentTimeMillis)) // 设置签发时间

    .setExpiration(new Date(currentTimeMillis + TOKEN_EXPIRE_MILLIS)) // 设置过期时间

    .addClaims(claimMap)

    .signWith(generateKey())

    .compact();

    }

    /**

    * 验证token

    * @param token

    * @return 0 验证成功,1、2、3、4、5 验证失败

    */

    public static int verifyToken(String token) {

    try {

    Jwts.parser().setSigningKey(generateKey()).parseClaimsJws(token);

    return 0;

    } catch (ExpiredJwtException e) {

    e.printStackTrace();

    return 1;

    } catch (UnsupportedJwtException e) {

    e.printStackTrace();

    return 2;

    } catch (MalformedJwtException e) {

    e.printStackTrace();

    return 3;

    } catch (SignatureException e) {

    e.printStackTrace();

    return 4;

    } catch (IllegalArgumentException e) {

    e.printStackTrace();

    return 5;

    }

    }

    /**

    * 解析token

    * @param token

    * @return

    */

    public static Map parseToken(String token) {

    return Jwts.parser() // 得到DefaultJwtParser

    .setSigningKey(generateKey()) // 设置签名密钥

    .parseClaimsJws(token)

    .getBody();

    }

    /**

    * 生成安全密钥

    * @return

    */

    public static Key generateKey() {

    return new SecretKeySpec(SECRET_KEY.getBytes(), SignatureAlgorithm.HS256.getJcaName());

    }

    }

    测试代码如下:

    //Map map = new HashMap();

    //map.put("userId", 1002);

    //map.put("userName", "张晓明");

    //map.put("age", 12);

    //map.put("address", "山东省青岛市李沧区");

    //String token = JwtUtils.createToken(map);

    //System.out.println(token);

    String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0ZWM2NWNhNC0wZjVmLTRlOTktOTI5NS1mYWUyN2UwODIzYzQiLCJpYXQiOjE1NzY0OTI4NjYsImV4cCI6MTU3NjQ5NjQ2NiwiYWRkcmVzcyI6IuWxseS4nOecgemdkuWym-W4guadjuayp-WMuiIsInVzZXJOYW1lIjoi5byg5pmT5piOIiwidXNlcklkIjoxMDAyLCJhZ2UiOjEyfQ.6Z18aIA6y52ntQkV3BwlYiVK3hL3R2WFujjTmuvimww";

    int result = JwtUtils.verifyToken(token);

    System.out.println(result);

    Map map = JwtUtils.parseToken(token);

    System.out.println(map);

    输出结果:

    0

    {jti=4ec65ca4-0f5f-4e99-9295-fae27e0823c4, iat=1576492866, exp=1576496466, address=山东省青岛市李沧区, userName=张晓明, userId=1002, age=12}

    签名算法

    12 种签名算法

    JWT 规范定义了12种标准签名算法:3种 secret key 算法和9种非对称密钥算法

    HS256: HMAC using SHA-256

    HS384: HMAC using SHA-384

    HS512: HMAC using SHA-512

    ES256: ECDSA using P-256 and SHA-256

    ES384: ECDSA using P-384 and SHA-384

    ES512: ECDSA using P-521 and SHA-512

    RS256: RSASSA-PKCS-v1_5 using SHA-256

    RS384: RSASSA-PKCS-v1_5 using SHA-384

    RS512: RSASSA-PKCS-v1_5 using SHA-512

    PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256

    PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384

    PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512

    根据算法名称可分为四类:HSxxx(secret key 算法)、ESxxx、RSxxx、PSxxx

    HSxxx、ESxxx 中的 xxx 表示算法 key 最小 Bit 长度

    RSxxx、PSxxx 中的 xxx 表示算法 key 最小 Byte 长度

    规定key的最小长度是为了避免因 key 过短生成弱密钥

    生成密钥

    jjwt 生成 secret key 两种方法

    String key = "1234567890_1234567890_1234567890";

    // 1. 根据key生成密钥(会根据字节参数长度自动选择相应的 HMAC 算法)

    SecretKey secretKey1 = Keys.hmacShaKeyFor(key.getBytes());

    // 2. 根据随机数生成密钥

    SecretKey secretKey2 = Keys.secretKeyFor(SignatureAlgorithm.HS256);

    方法 Keys.hmacShaKeyFor(byte[]) 内部也是 new SecretKeySpec(bytes, alg.getJcaName()) 来生成密钥的

    方法 Keys.secretKeyFor(SignatureAlgorithm) 内部使用 KeyGenerator.generateKey() 生成密钥

    jjwt 也提供了非对称密钥对的生成方法

    // 1. 使用jjwt提供的方法生成

    KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256); //or RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512

    // 2. 手动生成

    int keySize = 1024;

    // RSA算法要求有一个可信任的随机数源

    SecureRandom secureRandom = new SecureRandom();

    // 为RSA算法创建一个KeyPairGenerator对象

    KeyPairGenerator keyPairGenerator = null;

    try {

    keyPairGenerator = KeyPairGenerator.getInstance("RSA");

    } catch (NoSuchAlgorithmException e) {

    e.printStackTrace();

    }

    // 利用上面的随机数据源初始化这个KeyPairGenerator对象

    keyPairGenerator.initialize(keySize, secureRandom);

    // 生成密钥对

    KeyPair keyPair2 = keyPairGenerator.generateKeyPair();

    Keys.keyPairFor(SignatureAlgorithm) 会根据算法自动生成相应长度的

    signWith(secretKey) 会根据密钥长度自动选择相应算法,也可以指定任意算法(指定的算法不受密钥长度限制,可任意选择,即用 RS256生成的密钥,可以 signWith(secretKey, SignatureAlgorithm.RS512),但是 JJWT 并不建议这么做)

    在加密时使用 keyPair.getPrivate() ,解密时使用 keyPair.getPublic()

    不同密钥生成token

    以上都是使用同一密钥签名生成所有的token,下面我们使用不同的密钥

    这一个特性可以应用于不同用户/角色使用不同的密钥生成的 token,帮助你更好的构建权限系统

    首先在 Header(或 claims)中设置一个 keyId

    定义一个类,继承 SigningKeyResolverAdapter,并重写 resolveSigningKey() 或 resolveSigningKeyBytes() 方法

    public class MySigningKeyResolver extends SigningKeyResolverAdapter {

    @Override

    public Key resolveSigningKey(JwsHeader header, Claims claims) {

    // 除了从 header 中获取 keyId 外,也可以从 claims 中获取(前提是在 claims 中设置了 keyId 声明)

    String keyId = header.getKeyId();

    // 根据 keyId 查找相应的 key

    Key key = lookupVerificationKey(keyId);

    return key;

    }

    public Key lookupVerificationKey(String keyId) {

    // TODO 根据 keyId 获取 key,比如从数据库中获取

    // 下面语句仅做演示用,绝对不可用于实际开发中!!!

    String key = "qwertyuiopasdfghjklzxcvbnm2019_" + keyId;

    return Keys.hmacShaKeyFor(key.getBytes());

    }

    }

    解析时,不再调用 setSigningKey(SecretKey) ,而是调用 setSigningKeyResolver(SigningKeyResolver)

    // 生成密钥

    // TODO 此处 keyId 仅做演示用,实际开发中可以使用 UserId、RoleId 等作为 keyId

    String keyId = new Long(System.currentTimeMillis()).toString();

    System.out.println("keyId=" + keyId);

    String key = "qwertyuiopasdfghjklzxcvbnm2019_" + keyId;

    SecretKey secretKey = new SecretKeySpec(key.getBytes(), SignatureAlgorithm.HS256.getJcaName());

    // 1. 生成 token

    String token = Jwts.builder()

    .setHeaderParam(JwsHeader.KEY_ID, keyId) // 设置 keyId(当然也可以在 claims 中设置)

    .setSubject("JSON Web Token")

    .signWith(secretKey)

    .compact();

    System.out.println("token=" + token);

    // 2. 验证token

    // token 使用了不同的密钥生成签名,在解析时就不用调用 setSigningKey(SecretKey) 了

    // 而是调用 setSigningKeyResolver(SigningKeyResolver)

    try {

    Jwts.parser()

    .setSigningKeyResolver(new MySigningKeyResolver())

    .parseClaimsJws(token);

    // OK, we can trust this token

    System.out.println("token验证成功");

    } catch (JwtException e) {

    //don't trust the token!

    System.out.println("token验证失败");

    }

    安全加密

    敬请期待 .....

    展开全文
  • 我为我的Spring启动应用程序实现JWT身份验证.总的来说,它的工作原理如下:>客户端将用户名,密码发送到登录端点.>服务器检查提供的凭据是否有效.>如果不是,则会返回错误>如果是,它将返回一个令牌,该...

    我为我的

    Spring启动应用程序实现了JWT身份验证.总的来说,它的工作原理如下:

    >客户端将用户名,密码发送到登录端点.

    >服务器检查提供的凭据是否有效.

    >如果不是,则会返回错误

    >如果是,它将返回一个令牌,该令牌实际包含

    >客户端会在每个将来的请求中发送该令牌

    问题是,我们应该如何实施注销?

    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

    import org.springframework.security.core.Authentication;

    import org.springframework.security.core.userdetails.UserDetails;

    import org.springframework.security.core.userdetails.UserDetailsService;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import java.util.Date;

    class TokenAuthenticationService {

    static final long EXPIRATIONTIME = 864_000_000; // 10 days

    static final String SECRET = "ThisIsASecret";

    static final String TOKEN_PREFIX = "Bearer";

    static final String HEADER_STRING = "Authorization";

    static void addAuthentication(HttpServletResponse res,String username) {

    String JWT = Jwts

    .builder()

    .setSubject(username)

    .setExpiration(

    new Date(System.currentTimeMillis() + EXPIRATIONTIME))

    .signWith(SignatureAlgorithm.HS512,SECRET).compact();

    res.addHeader(HEADER_STRING,TOKEN_PREFIX + " " + JWT);

    }

    static Authentication getAuthentication(HttpServletRequest request,UserDetailsService customUserDetailsService) {

    String token = request.getHeader(HEADER_STRING);

    if (token != null) {

    // parse the token.

    Claims claims = Jwts.parser().setSigningKey(SECRET)

    .parseClaimsJws(token.replace(TOKEN_PREFIX,"")).getBody();

    String userName = claims.getSubject();

    Date expirationTime = claims.getExpiration();

    if (expirationTime.compareTo(new Date()) < 0) {

    return null;

    }

    UserDetails user = customUserDetailsService.loadUserByUsername(userName);

    return user != null ? new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword(),user.getAuthorities()) : null;

    }

    return null;

    }

    }

    jWTLoginFilter类使用addAuthentication在登录时发送身份验证代码,’getAuthentication由jWTAuthenticationFilter使用,用于过滤对端点的所有请求.

    这里的最佳做法是什么?

    展开全文
  • 因为现在要进行前后端分离开发,会产生跨域问题 ,所以要解决 两个问题 1、跨域名访问 2、使用 token令牌操作二、使用jwt解决 token问题:步骤:1)、pom.xml文件中导入com.google.code.gsongson2.6.2com.auth0java-...
  • JWT实现登录认证实例

    2021-03-08 16:18:54
    JWT全称JSON Web Token,是一个紧凑的,自包含的,安全的信息交换协议。JWT有很多方面的应用,例如权限认证,信息交换等。本文将简单介绍JWT登录权限认证的一个实例操作。JWT组成JWT由头部(Header),负载(Payload)和...
  • 先介绍下利用JWT进行鉴权的思路:1、用户发起登录请求。2、服务端创建一个加密后的JWT信息,作为Token返回。3、在后续请求中JWT信息作为请求头,发给服务端。4、服务端拿到JWT之后进行解密,正确解密表示此次请求...
  • 当没有损失的时间或增加的时间要考虑时,该测试通常会全年通过.但是现在这很令人讨厌....但是现在可以理解,当Java日期代码在初始化新的JWT Claim之后调用setExp()时,它们距未来一周还有一个小时的路程....
  • Java JWT的令牌机制

    2021-03-22 13:29:30
    JWT 简单介绍全称 Json Web Token 致力于网络安全的一套Json开放标准主要流程将用户部分信息进行加密,生成一套令牌,存放于客户端客户端发起请求时,带入此令牌,交由服务端识别令牌真伪服务端校验完成,开放部分...
  • Java的JJWT实现JWT

    2021-02-26 19:51:17
    1,什么是JJWTJJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。2,JJWT快速入门...
  • JWT实现登陆认证及Token自动续期

    千次阅读 2021-03-01 10:46:57
    扬长补短,因此在实际项目中选择的是使用JWT来进行认证 功能实现 JWT所需依赖 com.auth0  java-jwt 3.10.3 JWT工具类 public class JWTUtil { private static final Logger logger = LoggerFactory....
  • 什么是JWT?JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。此信息可以验证和信任,因为它是数字签名的。JWTs可以使用密钥(使用HMAC...
  • 下面介绍用jwt技术如何来实现单点登录。一、JWT定义及其组成JWT(JSON WEB TOKEN)是一个非常轻巧的规范,这个规范允许我们使用jwt在客户端和服务器之间传递安全可靠的信息。JWT由3个部分组成,分别是头部、载荷、签名...
  • 步骤实现功能一 : 登录成功后使用jwt生成随机码,并传递给浏览器(token) package com.czxy.service.impl;import com.czxy.domain.User;import com.czxy.mapper.UserMapper;import com.czxy.service.UserService;...
  • jwt身份验证

    2021-03-16 22:46:26
     jwt 上面的实现方式看着一大堆东西也是麻烦,又是传sessionId,又是引入redis,在分布式环境下有没有简单的方式啊! jwt全称JSON Web Token,我们之前每次都是传的sessionId,这个字符串是没有实际意义的,只是起...
  • 来源:www.cnblogs.com/better-farther-world2099一、什么是JWTJson web token (JWT), 是为了在网络应用环境间传递声明而执行的一种...
  • 有人说用security比较好,不用自己写,但是说实话,我用不好,乱七八糟的...话不多说,首先jwt工具类 import java.util.Date; import java.util.HashMap; import java.util.Map; import com.auth0.jwt.JWT; import com
  • 什么是JWTJSON Web Token(JWT)是一个开放的标准(RFC 7519),它定义了一个紧凑且自包含的方式,用于在各方之间以JSON对象安全地传输信息。这些信息可以通过数字签名进行验证和信任。可以使用秘密(使用HMAC算法)或使用...
  • } } /** * 我们可以将一些常用的信息放入token中,比如用户登陆信息,方便我们的使用 * 获得token中的信息无需secret解密也能获得 */ public static String getUsername(String token) { try { DecodedJWT jwt = JWT....
  • Java实现基于EC非对称加密,签名算法及实现ES256/ES512等JWT签名算法的大多使用BC(BouncyCastle)来实现。闲着无聊就用JDK自带的SunEC来实现了这些,请忽略英文注释。这文章主要用来记一下ES/PEM用java SunEC怎么写的...
  • 浅析JWT| JWT是啥子,Java构建JWT

    千次阅读 多人点赞 2021-01-26 11:09:43
    只是为了构建JWT请快步到相应的位置 正文目录 小声bbb 啥是JWT 细说JWT JWT 的几个特点 现在来完成一个JWT实现 第一步,导入maven 第二步,编写Token的生成逻辑 编写解密验证的逻辑 啥是JWT JWT的全称JSON Web ...
  • 前言项目前后端分离,请求认证使用的是JWT无状态认证。最近遇到一个问题,认证token需要从token中获取用户名,但是这个token有可能是过期的。一般取得用户名用的是下面的代码。private Claims getClaimsFromToken...
  • ---- 先来看下jwtjava实现。 com.auth0java-jwt3.10.2 使用jwt通常只需要两个步骤,1通过jwt来生成token,2验证token。 JwtUtil String = String = String MapStringStringclaimsAlgorithm algorithm = ...
  • 以前单体应用控制登录session就够了,...而且也很吃内存,相似原理的还可以用redis等缓存数据库弄一个共享缓存,也可以实现多客户端单点登录的功能,但是这两个的方法都要额外占用端口和服务,直到了解到JWTJWT...
  • 什么是 JWT这里是jwt 官方地址,想了解更多的可以在这里查看。jwt 全称是JSON Web Token,从全称就可以看出 jwt 多用于认证方面的。这个东西定义了一种简洁的,自包含的,安全的方法用于通信双方以 json 对象的形式...
  • javajwt+拦截器校验token获取用户信息 最近换工作,发现自己只会crud准备加强一下。结合网上资源写了一个用jwt生成并且校验token、校验token是在拦截器里面的,还有对异常的封装,响应体返回的封装,先写代码再...
  • 写在前面之前想尝试把JWT和Shiro结合到一起,但是在网上查了些博客...我之前写过一篇博客,可以看这里:Springboot实现JWT认证Shiro的Session机制由于我的方法是改变了Shiro的默认的Session机制,所以这里先简单讲一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,125
精华内容 8,450
关键字:

java实现jwt

java 订阅