本文以最簡配置搭建一個授權服務,讓大家初步瞭解授權服務及相關表。
token 存於數據庫中
例子基於Spring Boot 2.1.7.RELEASE ,使用mysql數據庫
參考資源: Authorization Server Configuration
- 添加一個實現了
AuthorizationServerConfigurer
接口的實現類且使用@EnableAuthorizationServer
註解進行標註
AuthorizationServerConfigurer
接口的實現類是AuthorizationServerConfigurerAdapter
,這裏我們繼承AuthorizationServerConfigurerAdapter
/**
* Created by liuquan on 2019/8/11.
*/
@Configuration
@EnableAuthorizationServer
public class CustomAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
}
}
@EnableAuthorizationServer
註解會導入兩個配置類AuthorizationServerEndpointsConfiguration
、AuthorizationServerSecurityConfiguration
- 我們來看看
AuthorizationServerEndpointsConfiguration
這個配置類
init()
會調用AuthorizationServerConfigurer
接口中的configure(AuthorizationServerEndpointsConfigurer endpoints)
方法,稍後我們將重寫該方法
這裏可以看出,如果我們沒有爲AuthorizationServerEndpointsConfigurer
設置tokenService
屬性,則默認使用DefaultTokenServices
從上圖可以看到DefaultTokenServices
中設置了TokenStore
對象,那TokenStore
是做什麼用的呢?
Persistence interface for OAuth2 tokens.
從代碼中的註釋可以知道TokenStore
是:OAuth2 令牌的持久化接口。其實現類有多個,如下圖:
如果沒有爲AuthorizationServerEndpointsConfigurer
對象設置tokenStore
屬性,則默認採用JwtTokenStore
或InMemoryTokenStore
,本例子採用數據庫存儲token,故重寫AuthorizationServerConfigurer
接口中的configure(AuthorizationServerEndpointsConfigurer endpoints)
方法設置tokenStore
@Configuration
@EnableAuthorizationServer
public class CustomAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Bean
public TokenStore tokenStore(){
return new JdbcTokenStore(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore());
}
}
- 我們來看看
AuthorizationServerSecurityConfiguration
這個配置類
圖上兩個方法會調用AuthorizationServerConfigurer
接口中的configure(ClientDetailsServiceConfigurer clients)
方法和configure(AuthorizationServerSecurityConfigurer security)
方法,稍後我們將重寫這兩個方法 - 我們來看看
ClientDetailsServiceConfiguration
這個配置類
35行,創建一個ClientDetailServiceBuilder
對象並通過構造函數傳入ClientDetailServiceConfigurer
對象,最終ClientDetailsServiceBuilder
對象是存入到SecurityConfigurerAdapter
類的securityBuilder
屬性中
ClientDetailsServiceConfigurer
是SecurityConfigurerAdapter
的子類,故46行中configurer.and()
得到的是securityBuilder
屬性,也就是35行存入的ClientDetailsServiceBuilder
對象
46行的configurer.and().build()
實際調用的是ClientDetailsServiceBuilder.build()
上圖中的82行拋出一個異常,也就是說我們不能直接使用ClientDetailsServiceBuilder
對象,那應該使用哪個對象呢?
ClientDetailsServiceBuilder
有兩個子類,這裏我們使用JdbcClientDetailsServiceBuilder
既然已經確定了替代類,那如何改變ClientDetailsServiceConfigurer
對象中的builder
對象呢
這時候就可以通過重寫AuthorizationServerConfigurer
接口中的configure(ClientDetailsServiceConfigurer clients)
方法來改變builder
對象
/**
* Created by liuquan on 2019/8/11.
*/
@Configuration
@EnableAuthorizationServer
public class CustomAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
}
注:以上只是解決方式之一,還有其它方式可以解決相同問題
- 我們來看看
AuthorizationServerSecurityConfigurer
這個配置類
AuthorizationServerSecurityConfigurer
對象中需要注入一個PasswordEncoder
,通過重寫AuthorizationServerConfigurer
接口中的configure(AuthorizationServerSecurityConfigurer security)
方法來實現
/**
* Created by liuquan on 2019/8/11.
*/
@Configuration
@EnableAuthorizationServer
public class CustomAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new CustomPasswordEncoder();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()")
.passwordEncoder(passwordEncoder());//若不設置會報錯
}
}
至此,授權服務最簡配置完成。
此處涉及三張表分別是oauth_client_details、oauth_access_token
、oauth_refresh_token
,Spring Security OAuth2提供了表結構
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
這裏提供mysql版本
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(255) NOT NULL,
`resource_ids` varchar(255) DEFAULT NULL,
`client_secret` varchar(255) DEFAULT NULL,
`scope` varchar(255) DEFAULT NULL,
`authorized_grant_types` varchar(255) DEFAULT NULL,
`web_server_redirect_uri` varchar(255) DEFAULT NULL,
`authorities` varchar(255) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` text,
`autoapprove` varchar(255) DEFAULT 'false',
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
`token_id` varchar(255) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(255) DEFAULT NULL,
`user_name` varchar(255) DEFAULT NULL,
`client_id` varchar(255) DEFAULT NULL,
`authentication` blob,
`refresh_token` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
`token_id` varchar(255) DEFAULT NULL,
`token` blob,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
相應的類爲:JdbcClientDetailsService
、JdbcTokenStore
表oauth_client_details
需要我們初始化
INSERT INTO `oauth_client_details` VALUES ('app', null, 'app', 'all', 'authorization_code,refresh_token,password,client_credentials', '', 'ADMIN', '60', '60', null, 'false');
oauth_client_details.resource_ids 爲空可訪問全部資源,多個資源ID用[,]分隔,限制可訪問的資源
oauth_client_details.authorized_grant_types 可選值:
authorization_code
、client_credentials
、implicit
、refresh_token
、password
- Postman 獲取 Token
請求結果