13-2、微服务统一认证 Spring Cloud OAuth2 + JWT--》JWT

本文介绍了JWT令牌的原理和结构,包括其包含的Header、Payload和Signature三部分。文章详细阐述了如何将认证服务器进行JWT改造,包括创建JWTTokenStore、JWTAccessTokenConverter以及设置签名密钥。同时,资源服务器不再依赖远程认证服务器,而是通过本地tokenStore进行JWT令牌的校验,实现无状态设置。

一、JWT令牌介绍

通过上边的测试我们发现,当资源服务和授权服务不在一起时资源服务使用RemoteTokenServices 远程请求授权服务验证token,如果访问量较⼤将会影响系统的性能。

解决上边问题: 令牌采用JWT格式即可解决上边的问题,用户认证通过会得到一个JWT令牌,JWT令牌中已经包括了用户相关的信 息,客户端只需要携带JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权。

1、什么是JWT?

JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对来签名,防止被篡改。

2、JWT令牌结构

JWT令牌由三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz

①Header

头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA),例如

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

将上边的内容使用Base64Url编码,得到一个字符串就是JWT令牌的第一部分。

②Payload

第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比 如:iss(签发者),exp(过期时间戳), sub(⾯向的用户)等,也可自定义字段。 此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。 最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分。 一个例子:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

③Signature

第三部分是签名,此部分用于防止jwt内容被篡改。 这个部分使用base64url将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明 签名算法进行签名。

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

base64UrlEncode(header):jwt令牌的第一部分。
base64UrlEncode(payload):jwt令牌的第二部分。
secret:签名所使用的密钥。

二、认证服务器JWT改造(Authorization Server)

lagou-cloud-oauth-server-9999–》OauthServerConfigurer
需要调整3处
在这里插入图片描述

 /**
     * 该方法用于创建tokenStore对象(令牌存储对象)
     * token以什么形式存储
     *
     * @return
     */
    private TokenStore tokenStore() {
//        return new InMemoryTokenStore();
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    /**
     * 返回jwt令牌转换器(帮助我们⽣成jwt令牌的)
     * 在这⾥,我们可以把签名密钥传递进去给转换器对象
     *
     * @return
     */
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey(sign_key);// 签名密钥
        jwtAccessTokenConverter.setVerifier(new MacSigner(sign_key)); // 验证时使用的密钥,和签名密钥保持一致
        return jwtAccessTokenConverter;
    }

    /**
     * 该方法用户获取一个token服务对象(该对象描述了token有效期等信息)
     *
     * @return
     */
    private AuthorizationServerTokenServices authorizationServerTokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setSupportRefreshToken(true); // 是否开启令牌刷新
        defaultTokenServices.setTokenStore(tokenStore());
        // 设置令牌有效时间(一般设置为2个小时)
        defaultTokenServices.setAccessTokenValiditySeconds(20);// 20秒
        // 设置刷新令牌的有效时间
        defaultTokenServices.setRefreshTokenValiditySeconds(3 * 24 * 60 * 60);

        // 针对jwt添加配置
        defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());
        return defaultTokenServices;
    }

说明
在这里插入图片描述

三、资源服务器校验JWT令牌

lagou-service-autodeliver-8098—》ResourceServerConfigurer
不需要和远程认证服务器交互,添加本地tokenStore

1、ResourceServerConfigurer

 /**
     * 该方法用于定义资源服务器向远程认证服务器发起请求,进行token校验等事宜
     *
     * @param resources
     * @throws Exception
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
//        super.configure(resources);

        /*// 1、设置当前资源服务的资源id
        resources.resourceId("autodeliver");

        // 2、定义token服务对象(token校验就应该靠token服务对象)
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        // 校验端点/接⼝设置
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:9999/oauth/check_token");
        remoteTokenServices.setClientId("client_lagou123");
        remoteTokenServices.setClientSecret("abcxyz");
        resources.tokenServices(remoteTokenServices);*/

        // jwt令牌改造:不需要和远程认证服务器交互,添加本地tokenStore
        resources.resourceId("autodeliver").tokenStore(tokenStore()).stateless(true);// 无状态设置
    }

2、将以下代码从上面的类中直接拷贝过来

//***************************************** 复用【开始】 *****************************************
    // 直接从com.lagou.edu.config.OauthServerConfigurer拷贝过来
    /**
     * 该方法用于创建tokenStore对象(令牌存储对象)
     * token以什么形式存储
     * @return
     */
    private TokenStore tokenStore() {
//        return new InMemoryTokenStore();
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    /**
     * 返回jwt令牌转换器(帮助我们⽣成jwt令牌的)
     * 在这⾥,我们可以把签名密钥传递进去给转换器对象
     * @return
     */
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey(sign_key);// 签名密钥
        jwtAccessTokenConverter.setVerifier(new MacSigner(sign_key)); // 验证时使用的密钥,和签名密钥保持一致
        return jwtAccessTokenConverter;
    }
//***************************************** 复用【结束】 *****************************************

四、测试

获取token的接口返回值已经变成这样的了在这里插入图片描述

五、jwt生成的token解析

jwt官网
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值