【Spring Security OAuth2】- App认证框架- 令牌配置

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

令牌配置

接下来的内容是:

  • 基本的Token参数配置
  • 使用jwt替换默认的token
  • 扩展和解析jwt的信息

token 的处理在认证服务器处理的。之前已经配置了资源服务器,现在来自定义认证服务器

spirng boot 2 的自动配置文件和1.5的不一样
直接跟着视频走是不会成功的,原因如下

OAuth2AuthorizationServerConfiguration 类是 @EnableAuthorizationServer 的自动配置类;
如果我们 继承了 AuthorizationServerConfigurerAdapter,那么该类将不会被初始化,认证服务器将不能正常工作
(看源码中的条件注解声明得知)

这是根据自动配置类简化而来的配置。正常使用

    package cn.mrcode.imooc.springsecurity.securityapp;
    
    /**
     * ${desc}
     * @author zhuqiang
     * @version 1.0.1 2023/8/7 10:52
     * @date 2023/8/7 10:52
     * @since 1.0
     */
    @Configuration
    @EnableAuthorizationServer
    public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
        private final AuthenticationManager authenticationManager;
    //    @Autowired
    //    private PasswordEncoder passwordEncoder;
    
        public MyAuthorizationServerConfig(
                AuthenticationConfiguration authenticationConfiguration) throws Exception {
            this.authenticationManager = authenticationConfiguration.getAuthenticationManager();
        }
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("myid")
                    .secret("myid")
                    .redirectUris("http://example.com", "http://ora.com")
                    .and()
                    .withClient("myid2")
                    .secret("myid2")
                    .redirectUris("http://example.com", "localhost:8080")
                    .authorizedGrantTypes("refresh_token", "password")
                    .accessTokenValiditySeconds(7200)
                    .scopes("all", "read", "write");
        }
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.authenticationManager(this.authenticationManager);
        }
    
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            // 这里使用什么密码需要 根据上面配置client信息里面的密码类型决定
            // 目前上面配置的是无加密的密码
            security.passwordEncoder(NoOpPasswordEncoder.getInstance());
        }
    }

抽成配置

下面记录下一些注意的地方

yml中数组和对象嵌套的写法如下:

    imooc:
      security:
        oauth2:
          clients:
            -
              clientId: myid
              clientSecret: myid
              redirectUris:
                - "http://example.com"
                - "http://ora.com"
              accessTokenValiditySeconds: 0
            -
              clientId: myid2
              clientSecret: myid2
              authorizedGrantTypes: ["refresh_token", "password"]
              redirectUris:
                - "http://example.com"
                - "localhost:8080"
              scopes: ["all", "read", "write"]
              accessTokenValiditySeconds: 7200

配置类对应,注意看下面的数组。都是默认为空数组,这样不会导致代码中npe

    public class OAuth2Properties {
        private OAuth2ClientProperties[] clients = {};
    
    public class OAuth2ClientProperties {
        private String clientId;
        private String clientSecret;
        private String[] authorizedGrantTypes = {};
        private String[] redirectUris = {}; // 信任的回调域
        private String[] scopes = {};
        private int accessTokenValiditySeconds; // token有效期

配置使用的地方

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        InMemoryClientDetailsServiceBuilder inMemory = clients.inMemory();
        OAuth2ClientProperties[] clientsInCustom = securityProperties.getOauth2().getClients();
        for (OAuth2ClientProperties p : clientsInCustom) {
            inMemory.withClient(p.getClientId())
                    .secret(p.getClientSecret())
                    .redirectUris(p.getRedirectUris())
                    .authorizedGrantTypes(p.getAuthorizedGrantTypes())
                    .accessTokenValiditySeconds(p.getAccessTokenValiditySeconds())
                    .scopes(p.getScopes());
        }
        logger.info(Arrays.toString(clientsInCustom));
    }

tokenStore 使用redis来存储

上面的配置都是使用的内存来存储令牌信息;令牌的存储和获取比较频繁,为了能持久化。使用redis

在认证服务配置类中配置tokenStore即可

    cn.mrcode.imooc.springsecurity.securityapp.MyAuthorizationServerConfig
    
    @Autowired(required = false)
    public TokenStore tokenStore;
    
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(this.authenticationManager);
        endpoints.tokenStore(tokenStore);
    }

TokenStore 需要使用的地方初始化对象,也就是app中

    package cn.mrcode.imooc.springsecurity.securityapp;
    
    import cn.mrcode.imooc.springsecurity.securitycore.MyRedisTokenStore;
    
    @Configuration
    public class TokenStoreConfig {
        @Autowired
        private RedisConnectionFactory redisConnectionFactory;
    
        @Bean
        public TokenStore tokenStore() {
            return new MyRedisTokenStore(redisConnectionFactory);
        }
    }

注意在spring boot 2.0.4 中;使用默认的 RedisTokenStore 在存储的时候会出现异常;

解决方案:把RedisTokenStore的代码完全copy一份,然后把 storeAccessToken 方法中调用
conn.set的代码全部缓存 conn.stringCommands().set

    @Override
       public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
           byte[] serializedAccessToken = serialize(token);
           byte[] serializedAuth = serialize(authentication);
           byte[] accessKey = serializeKey(ACCESS + token.getValue());
           byte[] authKey = serializeKey(AUTH + token.getValue());
           byte[] authToAccessKey = serializeKey(AUTH_TO_ACCESS + authenticationKeyGenerator.extractKey(authentication));
           byte[] approvalKey = serializeKey(UNAME_TO_ACCESS + getApprovalKey(authentication));
           byte[] clientId = serializeKey(CLIENT_ID_TO_ACCESS + authentication.getOAuth2Request().getClientId());
    
           RedisConnection conn = getConnection();
           try {
               conn.openPipeline();
               // 这里 set的时候,子类都不支持存储自己数组
               conn.stringCommands().set(accessKey, serializedAccessToken);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值