当前位置: 首页 > article >正文

SpringSecurity(18)——OAuth2授权码管理

AuthorizationCodeServices

public interface AuthorizationCodeServices {

	//为指定的身份验证创建授权代码。
	String createAuthorizationCode(OAuth2Authentication authentication);

	//使用授权码。
	OAuth2Authentication consumeAuthorizationCode(String code)throws InvalidGrantException;
}

public abstract class RandomValueAuthorizationCodeServices implements AuthorizationCodeServices {

	private RandomValueStringGenerator generator = new RandomValueStringGenerator();

	public String createAuthorizationCode(OAuth2Authentication authentication) {
		String code = generator.generate();
		store(code, authentication);
		return code;
	}

	public OAuth2Authentication consumeAuthorizationCode(String code) throws InvalidGrantException {
		OAuth2Authentication auth = this.remove(code);
		if (auth == null) {throw new InvalidGrantException("Invalid authorization code: " + code);}
		return auth;
	}

    protected abstract void store(String code, OAuth2Authentication authentication);
    protected abstract OAuth2Authentication remove(String code);
}

RandomValueAuthorizationCodeServices为我们指定了授权码的生成方式,同时也开放了授权码的存储和删除。这为我们后面AuthorizationCodeServices的自定义提供了方便,因为我们只要继承RandomValueAuthorizationCodeServices,实现他的store和remove方法就行了。
RandomValueAuthorizationCodeServices有2个子类InMemoryAuthorizationCodeServices和JdbcAuthorizationCodeServices,一个是把授权码存储到内存中,另一个是把授权码存储到数据库中。

JDBC管理授权码

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.3.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.3.12.RELEASE</version>
</dependency>
@Configuration
public class MyOauth2Config {

    /**
     * druid数据源
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    /**
     * jdbc管理令牌
     */
    @Bean
    public TokenStore jdbcTokenStore() {
        return new JdbcTokenStore(druidDataSource());
    }

    /**
     * 授权码管理策略
     */
    @Bean
    public AuthorizationCodeServices jdbcAuthorizationCodeServices() {
        //使用jdbc方式保存授权码到oauth_code中
        return new JdbcAuthorizationCodeServices(druidDataSource());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
/**
 * 当前需要使用内存方式存储了用户令牌,应当使用UserDetailsService才行,否则会报错
 */
@Component
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return new User("admin", passwordEncoder.encode("123456"),
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin_role"));
    }
}
@EnableWebSecurity
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailService myUserDetailService;

    /**
     * password密码模式要使用此认证管理器
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 用户类信息
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService);
    }
}
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthenticationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private TokenStore tokenStore;
    
    @Autowired
    private AuthorizationCodeServices jdbcAuthorizationCodeServices;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("test-pc")
                .secret(passwordEncoder.encode("123456"))
                .resourceIds("oauth2-server")
                .authorizedGrantTypes("authorization_code", "password", "implicit", "client_credentials", "refresh_token")
                .scopes("all")
                .autoApprove(false)
                .redirectUris("http://www.baidu.com");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.userDetailsService(myUserDetailsService);
        //令牌管理策略
        endpoints.tokenStore(tokenStore);
        //授权码管理策略,针对授权码模式有效,会将授权码放到oauth_code表,授权后就删除它
        endpoints.authorizationCodeServices(jdbcAuthorizationCodeServices);
    }
}

image.png

自定义Redis管理授权码

@Service
public class RedisAuthorizationCodeServices extends RandomValueAuthorizationCodeServices {

    String AUTH_CODE_PREFIX = "yiyi:code:auth:";

    private final RedisRepository redisRepository;
    private final RedisSerializer<Object> valueSerializer;

    public RedisAuthorizationCodeServices(RedisRepository redisRepository) {
        this.redisRepository = redisRepository;
        this.valueSerializer = RedisSerializer.java();
    }

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 将存储code到redis,并设置过期时间,10分钟
     */
    @Override
    protected void store(String code, OAuth2Authentication authentication) {
        redisRepository.setExpire(redisKey(code), authentication, 10, TimeUnit.MINUTES, valueSerializer);
    }

    @Override
    protected OAuth2Authentication remove(final String code) {
        String codeKey = redisKey(code);
        OAuth2Authentication token = (OAuth2Authentication) redisRepository.get(codeKey, valueSerializer);
        redisRepository.del(codeKey);
        return token;
    }

    /**
     * redis中 code key的前缀
     */
    private String redisKey(String code) {
        return AUTH_CODE_PREFIX + code;
    }
}
@Configuration
@EnableAuthorizationServer
public class Authorizationservercontig2 extends AuthorizationServerConfigurerAdapter {

    //忽略代码.....
    @Autowired
    private RandomValueAuthorizationCodeServices authorizationCodeServices;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
         //忽略代码....
         endpoints .authorizationCodeServices(authorizationCodeServices)
         //忽略代码....
    }
}

http://www.kler.cn/a/229262.html

相关文章:

  • 使用 WPF 和 C# 将纹理应用于三角形
  • 闲谭SpringBoot--ShardingSphere分布式事务探究
  • JAVA:在IDEA引入本地jar包的方法(不读取maven目录jar包)
  • SK海力士(SK Hynix)是全球领先的半导体制造商之一,其在无锡的工厂主要生产DRAM和NAND闪存等存储器产品。
  • .NET8.0多线程编码结合异步编码示例
  • 王炸组合:Dolphinscheudler 3.1.*搭配SeaT unnel2.3.*高效完成异构数据数据集成
  • Unix五种I/O模型(阻塞、非阻塞、多路复用、信号驱动、异步)
  • 网络选择流程分析(首选网络类型切换流程)
  • Allegro如何把Symbols,shapes,vias,Clines,Cline segs等多种元素一起移动
  • Visual Studio 20XX控制台程序鼠标点击阻塞问题
  • 【开源】JAVA+Vue+SpringBoot实现二手车交易系统
  • 【Java八股面试系列】JVM-垃圾回收
  • 【芯片设计- RTL 数字逻辑设计入门 6 -- 带同步复位的D触发器 RTL实现及testbench 验证】
  • 【Spring Boot 3】应用启动执行特定逻辑
  • 【leetcode热题100】删除排序数组中的重复项 II
  • YOLO-World: Real-Time Open-Vocabulary Object Detection
  • SQL 表信息 | 统计 | 脚本
  • Polar-Net:通过 OCTA(光学相干断层扫描血管成像)检测阿尔茨海默病
  • CXYGZL - 年前最后一波更新了~
  • IDEA创建SpringBoot+Mybatis-Plus项目
  • docer compose部署simple-docker
  • SpringMVC-请求
  • 【实训】网络规划与部署实训
  • javaEE - 23( 21000 字 Servlet 入门 -1 )
  • 实践:微服务版本升级步骤以及maven仓库相关概念
  • python增量同步文件夹中的文件