ClientDetailsService
public interface ClientDetails extends Serializable {String getClientId();//客户端idSet<String> getResourceIds();//此客户端可以访问的资源。如果为空,则调用者可以忽略boolean isSecretRequired();//验证此客户端是否需要secretString getClientSecret();//获取客户端的secretboolean isScoped();//此客户端是否仅限于特定范围Set<String> getScope();//此客户端的范围。如果客户端未确定作用域,则为空Set<String> getAuthorizedGrantTypes();//此客户端被授权的授权类型Set<String> getRegisteredRedirectUri();//此客户端的预定义重定向redirect_urlCollection<GrantedAuthority> getAuthorities();//权限集合Integer getAccessTokenValiditySeconds();//访问令牌有效期Integer getRefreshTokenValiditySeconds();//刷新令牌有效期boolean isAutoApprove(String scope);//测试客户端是否需要特定范围的用户批准Map<String, Object> getAdditionalInformation();//额外的信息
}
public interface ClientDetailsService {//通过clientId获取客户端详情信息ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException;
}
客户端详情(Client Details)能够在应用程序运行的时候进行更新,可以通过访问底层的存储服务(例如将客户端详情存储在一个关系数据库的表中,就可以使用 JdbcClientDetailsService)或者通过 ClientDetailsManager 接口(同时你也可以实现 ClientDetailsService 接口)来进行管理
JDBC存储客户端信息
client_secret:客户端密码,此处不能是明文,需要加密
<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管理令牌*/@Beanpublic TokenStore jdbcTokenStore() {return new JdbcTokenStore(druidDataSource());}/*** 授权码管理策略*/@Beanpublic AuthorizationCodeServices jdbcAuthorizationCodeServices() {//使用jdbc方式保存授权码到oauth_code中return new JdbcAuthorizationCodeServices(druidDataSource());}/*** 使用jdbc方式管理客户端信息*/@Beanpublic ClientDetailsService jdbcClientDetailsService(){return new JdbcClientDetailsService(druidDataSource());}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
/*** 当前需要使用内存方式存储了用户令牌,应当使用UserDetailsService才行,否则会报错*/
@Component
public class MyUserDetailService implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {return new User("admin", passwordEncoder.encode("123456"),AuthorityUtils.commaSeparatedStringToAuthorityList("admin_role"));}
}
@EnableWebSecurity
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate MyUserDetailService myUserDetailService;/*** password密码模式要使用此认证管理器*/@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** 用户类信息*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(myUserDetailService);}
}
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthenticationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate MyUserDetailsService myUserDetailsService;@Autowiredprivate TokenStore tokenStore;@Autowiredprivate AuthorizationCodeServices jdbcAuthorizationCodeServices;@Autowiredprivate ClientDetailsService jdbcClientDetailsService;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(jdbcClientDetailsService);}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager);endpoints.userDetailsService(myUserDetailsService);//令牌管理策略endpoints.tokenStore(tokenStore);//授权码管理策略,针对授权码模式有效,会将授权码放到oauth_code表,授权后就删除它endpoints.authorizationCodeServices(jdbcAuthorizationCodeServices);}
}