jwt + redis 登录

jwt + redis 登录

在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token认证机制。Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

导包


    com.auth0
    java-jwt
    3.2.0

工具类

JwtHelper jwt生成器

jks证书自行百度生成方法。

public class JwtHelper {
    //设置发行人
    private static final String ISSUER = "user";

    public static String genToken(Map claims){
        try {
        //这里的JwtRsaUtil是自定义的另一个工具类,用于从jks证书文件中提取公钥和私钥,进行RSA加密解密
            JwtRsaUtil jwtRsaUtil = new JwtRsaUtil("/*****.jks", "*****".toCharArray());
            //获取秘钥对
            KeyPair keyPair = jwtRsaUtil.getKeyPair();
            //然后就是设置加密算法了,可以选择许多不同的加密算法,这里使用的RSA256非对称加密,安全性更好。如果为了方便,也可以使用HS256对称加密
            Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) keyPair.getPublic(), (RSAPrivateKey) keyPair.getPrivate());
            //开始构建JWT,这里可以设置很多信息,我只设置了发行人和过期时间
            JWTCreator.Builder builder = JWT.create().withIssuer(ISSUER).withExpiresAt(DateUtils.addDays(new Date(), 1));
            //然后把传入的claims放进builder里面,这里使用了java8的方法引用,也可以说是lambda的简化写法吧,本来写的lambda表达式,然后idea提示这里还可以简化,然后就变成这样子了。。
            claims.forEach(builder::withClaim);
            //签名之后返回
            return builder.sign(algorithm);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        }
    }
    //验签方法
    public static Map verifyToken(String token)  {
        Algorithm algorithm = null;
        try {
            KeyPair keyPair = JwtRsaUtil.getInstance().getKeyPair();
            algorithm = Algorithm.RSA256((RSAPublicKey) keyPair.getPublic(), (RSAPrivateKey) keyPair.getPrivate());
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        }
        JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
        DecodedJWT jwt =  verifier.verify(token);
        Map map = jwt.getClaims();
        Map resultMap = Maps.newHashMap();
        map.forEach((k,v) -> resultMap.put(k, v.asString()));
        return resultMap;
    }
}

JwtRsaUtil 解析jks文件的工具类

public class JwtRsaUtil {

    private String keyStoreFile;
    private char[] password;
    private KeyStore store;
    private Object lock = new Object();

    private static JwtRsaUtil instance = null;

    public static JwtRsaUtil getInstance() {
        synchronized (JwtRsaUtil.class) {
            if (instance == null) {
                synchronized (JwtRsaUtil.class) {
                //这里是jks文件路径和密码
                    instance = new JwtRsaUtil("/******.jks", "******".toCharArray());
                }
            }
            return instance;
        }
    }

    public JwtRsaUtil(String _jksFilePath, char[] password) {
        this.keyStoreFile = _jksFilePath;
        this.password = password;
    }

    public KeyPair getKeyPair() {
        return getKeyPair("*******", this.password);
    }

    public KeyPair getKeyPair(String alias, char[] password) {
        try {
            synchronized (this.lock) {
                if (this.store == null) {
                    synchronized (this.lock) {
                        InputStream is = this.getClass().getResourceAsStream(keyStoreFile);
                        try {
                            this.store = KeyStore.getInstance("JKS");
                            this.store.load(is, this.password);
                        } finally {
                            if (is != null) {
                                try {
                                    is.close();
                                } catch (Exception e) {
                                }
                            }
                        }
                    }
                }
            }
            RSAPrivateCrtKey key = (RSAPrivateCrtKey) this.store.getKey(alias, password);
            RSAPublicKeySpec spec = new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent());
            PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(spec);
            return new KeyPair(publicKey, key);
        } catch (Exception e) {
            throw new IllegalStateException("Cannot load keys from store: " + this.keyStoreFile, e);
        }
    }
}

登录

登录的时候需要将token存入redis

        // 生成JWT
        Map claims = new HashMap<>();
        claims.put("id", user.getId()+"");
        claims.put("nickName", user.getNickName());
        claims.put("login_method", userSocial.getLoginMethod());
        claims.put("openId", userSocial.getUnionId());
        claims.put("ts", Instant.now().getEpochSecond()+"");
        String jwtToken = JwtHelper.genToken(claims);
        // 缓存至redis
        renewToken(jwtToken, user.getId());
        return jwtToken;
        
        
        
        private void renewToken(String token, int id) {
        redisTemplate.opsForValue().set(id, token);
        redisTemplate.expire(id, 30, TimeUnit.MINUTES);
    	}

退出登录

退出登录时从redis中删除

    public void invalidate(String token) {
        Map map = JwtHelper.verifyToken(token);
        redisTemplate.delete(map.get("id"));
    }

你可能感兴趣的:(JAVA,redis,java,web安全,分布式)