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

AuthorizationCodeServices

public interface AuthorizationCodeServices {

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

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

SpringSecurity(18)——OAuth2授权码管理_第1张图片

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.bootgroupId>
    <artifactId>spring-boot-starter-securityartifactId>
    <version>2.3.12.RELEASEversion>
dependency>
<dependency>
    <groupId>org.springframework.security.oauthgroupId>
    <artifactId>spring-security-oauth2artifactId>
    <version>2.3.4.RELEASEversion>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
    <version>2.3.12.RELEASEversion>
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)
         //忽略代码....
    }
}

你可能感兴趣的:(SpringSecurity,java,spring,oauth2)