使用JWT替换默认令牌token

JSON Web Token (JWT)

自包含

token的创建

org.springframework.security.oauth2.provider.token.DefaultTokenServices#createAccessToken(org.springframework.security.oauth2.provider.OAuth2Authentication, org.springframework.security.oauth2.common.OAuth2RefreshToken)

在这里插入图片描述

总结

可见token根据UUID生成的
所以token里面的信息是无意义的
看上节redis里面token的存储,是把相关信息与token做了关联
如过redis服务器挂掉了,那么这个token就是毫无意义的,以为他本身不包含任何信息

jwt 恰恰相反,它是自包含了相关的信息

密签

密签的意思 不是 jwt 信息的加密或解密

他是指如果 jwt 里面的信息被修改以后 我们能够通过密签发现

jwt不能存储敏感信息

可扩展

可以在里面放任何数据

替换默认token

TokenStoreConfig

这个配置里面配置了两个TokenStore
根据不同的配置确认token的类型
默认是JwtTokenStore

@Configuration
public class TokenStoreConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    @ConditionalOnProperty(prefix = "whale.security.oauth2",name = "storeType",havingValue = "redis",matchIfMissing = false)
    public TokenStore tokenStore(){
        return new RedisTokenStore(redisConnectionFactory);
    }

    @Configuration
    @ConditionalOnProperty(prefix = "whale.security.oauth2",name = "storeType",havingValue = "jwt",matchIfMissing = true)
    //prefix 是只application配置文件中 配置的最后一个点分隔后前面的一部分 这叫前缀
    //name  对应的是后缀 最后一个点分隔后的后面的那部分
    //即检查的配置项为 whale.security.oauth2.storeType
    //havingValue = "jwt"  当配置项的值为jwt的时候 这个类里面的所有配置生效
    //matchIfMissing 如果配置文件里没有找到这个属性,即默认生效
    public static class JwtTokenConfig{

        @Autowired
        private SecurityProperties securityProperties;

        //token 的存储
        @Bean
        public TokenStore jwtTokenStore(){
            return new JwtTokenStore(jwtAccessTokenConverter());
        }

        //token生成处理
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter(){
            JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
            jwtAccessTokenConverter.setSigningKey(securityProperties.getOauth2().getJwtSigningKey());
            return  jwtAccessTokenConverter;
        }
    }

}

WhaleAuthenticationServiceConfig

在这里插入图片描述

OAuth2Properties

/**
     * 这个是秘钥 一定要保存好
     *
     * 发出去的令牌要用它签名
     * 收到的令牌也要用它来验签
     *
     * jwt 是token的标准协议,唯一的安全性就是这个秘钥
     *
     */
    private String jwtSigningKey = "whale";

测试 jwt

用表单登录获取token的方式
发现 这次的 access_token 很长
在这里插入图片描述

"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTg2MDg5NjQsInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiYWRtaW4iLCJST0xFX1VTRVIiXSwianRpIjoiMzYzNjJiZWUtMjFjOS00ZWM3LWIxMmUtYjQyYzYyYzViZjI5IiwiY2xpZW50X2lkIjoid2hhbGUiLCJzY29wZSI6WyJhbGwiLCJyZWFkIiwid3JpdGUiXX0.PJ1vcPCccfVfrHxCJzRs19xoFV6hnu5lMetJuYARylw",

https://jwt.io/ jwt解析
在这里插入图片描述访问资源成功
在这里插入图片描述

jwt token加额外信息

实现TokenEnhancer

在这里插入图片描述

WhaleTokenEnhancer

public class WhaleTokenEnhancer implements TokenEnhancer {
    /**
     *
     * @param oAuth2AccessToken
     * @param oAuth2Authentication
     * @return
     */
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {

        Map<String,Object> info = new HashMap<>();
        info.put("company","埃森哲");

        ((DefaultOAuth2AccessToken)oAuth2AccessToken).setAdditionalInformation(info);

        return oAuth2AccessToken;
    }
}

TokenStoreConfig 配置 TokenEnhancer bean

·······························
  public static class JwtTokenConfig{

    		·····················
        @Bean
        @ConditionalOnMissingBean(name = "jwtTokenEnhancer")
        public TokenEnhancer jwtTokenEnhancer(){
            return  new WhaleTokenEnhancer();
        }
    }

WhaleAuthenticationServiceConfig 中配置tokenEnhancerChain

部分代码如下


    @Autowired(required = false)
    private TokenEnhancer jwtTokenEnhancer;

    /**
     *
     * @param endpoints  oauth/token 的入口点
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//        super.configure(endpoints);
//        endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsService);
        endpoints.tokenStore(tokenStore)
                 .authenticationManager(authenticationManager)
                 .userDetailsService(userDetailsService);

        if(jwtAccessTokenConverter!=null && jwtTokenEnhancer!=null){

            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();

            List<TokenEnhancer> enhancers = new ArrayList<>();
            enhancers.add(jwtTokenEnhancer);
            enhancers.add(jwtAccessTokenConverter);

            tokenEnhancerChain.setTokenEnhancers(enhancers);

            endpoints.tokenEnhancer(tokenEnhancerChain)
                     .accessTokenConverter(jwtAccessTokenConverter);
        }
    }

测试

在这里插入图片描述eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCIsInJlYWQiLCJ3cml0ZSJdLCJjb21wYW55Ijoi5ZD5qOu5ZOyIiwiZXhwIjoxNTU4NjEzNjQzLCJhdXRob3JpdGllcyI6WyJhZG1pbiIsIlJPTEVfVVNFUiJdLCJqdGkiOiI5OTA3NWZjOC04MTI3LTQ2YWYtYTM2OS0wNTlkODlkNTIwMTEiLCJjbGllbnRfaWQiOiJ3aGFsZSJ9.1Ild0mbgxQn1No0NQIQI2gWrTDFDcgdHYHdC_kdGq_w

解析如下

在这里插入图片描述

Authentication解析额外信息?

注意 虽然我们的jwt可以携带额外信息
但是 我们的spring 只是 将 jwt规范里面的信息解析成 Authentication
在这里插入图片描述
如果我们需要jwt token 里的额外信息呢?

为此我们需要加入新的依赖

https://jwt.io/
https://www.jsonwebtoken.io/

demo pom 文件中加依赖

试了几个 0.9.0 版本可以

 <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
解析额外信息 UserController
    @GetMapping("/me11")
    public Object getCurrentUser11(Authentication authentication, HttpServletRequest request) throws UnsupportedEncodingException {
        //spring 会自动找到Authentication类型的数据注入
        String header = request.getHeader("Authorization");
        String token = StringUtils.substringAfter(header, "Bearer ");

        //需要用秘钥来验证签名
        //注意 签名的时候 默认用的是秘钥的utf-8编码 ,同时验签的时候也要知道 编码 utf-8
        Claims claims = Jwts.parser().setSigningKey(securityProperties.getOauth2().getJwtSigningKey().getBytes("utf-8"))
                .parseClaimsJws(token).getBody();

        String company = (String) claims.get("company");

        System.out.println(company);
        return  authentication;
    }
测试

在这里插入图片描述
在这里插入图片描述

token令牌的刷新

refresh_token

在用户无感的情况下用refresh_token得到一个新的token
在这里插入图片描述

测试

但我的refresh_token没有测试成功
也不知道什么原因

在这里插入图片描述

按道理是完全可以的,也不知道问题出在哪

https://auth0.com/docs/tokens/refresh-token/current#9e51c5c22d4b450cab209018dc3be588_java

Use a Refresh Token
To exchange the Refresh Token you received during authorization for a new Access Token, make a POST request to the /oauth/token endpoint in the Authentication API, using grant_type=refresh_token.

curl --request POST \
  --url 'https://YOUR_DOMAIN/oauth/token' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data 'grant_type=refresh_token&client_id=%24%7Baccount.clientId%7D&client_secret=YOUR_CLIENT_SECRET&refresh_token=YOUR_REFRESH_TOKEN'

https://openapi.baidu.com/wiki/index.php?title=使用Refresh_Token获取Access_Token

https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/

https://auth0.com/docs/tokens/refresh-token/current

https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/

https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#acquiring--client-ids-and-secrets

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值