1:項目入門DEMO
1:POM文件
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hujiang.boot</groupId>
<artifactId>auth-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>auth-service</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
2:Main方法
@Configuration
@ComponentScan
@EnableAutoConfiguration
@RestController
@SessionAttributes("authorizationRequest")
@EnableResourceServer
public class AuthserverApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(AuthserverApplication.class, args);
}
@RequestMapping("/hello")
public String hello() {
return "hello";
}
@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("acme").secret("acmesecret")
.authorizedGrantTypes("client_credentials").scopes("openid");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
}
}
3:測試:
通過curl http://localhost:8080/hello訪問,返回認證失敗
{"error":"unauthorized","error_description":"Fullauthentication is required to access this resource"}
先拿到訪問TOKEN
curl -v -X POST"acme:acmesecret@localhost:8080/oauth/token?grant_type=client_credentials"
{"access_token":"b92fd988-d95b-427c-84bf-65da969e45f0","token_type":"bearer","expires_in":42933,"scope":"openid"}
請求接口:
curl -H "Authorization:Bearerb92fd988-d95b-427c-84bf-65da969e45f0" http://localhost:8080/hello
或者curl http://localhost:8080/hello?access_token=b92fd988-d95b-427c-84bf-65da969e45f0
返回hello
2:通過http請求,驗證TOKEN的有效性
1:默認配置
驗證token
正確:
失敗:
總結:這種方式不適合我們項目,A調用B時,不能把A的client_id和secret也傳遞給B。
如果不傳遞,默認情況下/oauth/check_token是受保護的接口;如果B不需要調用其他的服務,是不需要註冊的,所以直接調用該接口,會提示未認證。
2:修改配置,/oauth/check_token暴露出去,不受oauth保護
applicationContext.properties添加如下配置
security.ignored=/welcome,/oauth/check_token
正確:
失敗:
3:如何配置JDBC數據庫
http://andaily.com/spring-oauth-server/db_table_description.html
1:代碼修改
2:創建數據庫表
-- used in tests that use HSQL
create table oauth_client_details (
client_id VARCHAR(256) PRIMARY KEY,
resource_ids VARCHAR(256),
client_secret VARCHAR(256),
scope VARCHAR(256),
authorized_grant_types VARCHAR(256),
web_server_redirect_uri VARCHAR(256),
authorities VARCHAR(256),
access_token_validity INTEGER,
refresh_token_validity INTEGER,
additional_information VARCHAR(4096),
autoapprove VARCHAR(256)
);
create table oauth_client_token (
token_id VARCHAR(256),
token LONGVARBINARY,
authentication_id VARCHAR(256) PRIMARY KEY,
user_name VARCHAR(256),
client_id VARCHAR(256)
);
create table oauth_access_token (
token_id VARCHAR(256),
token LONGVARBINARY,
authentication_id VARCHAR(256) PRIMARY KEY,
user_name VARCHAR(256),
client_id VARCHAR(256),
authentication LONGVARBINARY,
refresh_token VARCHAR(256)
);
create table oauth_refresh_token (
token_id VARCHAR(256),
token LONGVARBINARY,
authentication LONGVARBINARY
);
create table oauth_code (
code VARCHAR(256), authentication LONGVARBINARY
);
create table oauth_approvals (
userIdVARCHAR(256),
clientIdVARCHAR(256),
scopeVARCHAR(256),
statusVARCHAR(10),
expiresAtTIMESTAMP,
lastModifiedAtTIMESTAMP
);
-- customized oauth_client_details table
create table ClientDetails (
appId VARCHAR(256) PRIMARY KEY,
resourceIds VARCHAR(256),
appSecret VARCHAR(256),
scope VARCHAR(256),
grantTypes VARCHAR(256),
redirectUrlVARCHAR(256),
authorities VARCHAR(256),
access_token_validity INTEGER,
refresh_token_validity INTEGER,
additionalInformation VARCHAR(4096),
autoApproveScopes VARCHAR(256)
);
3:測試
沒有數據時:
執行SQL插入一條記錄:
insert oauth_client_details(client_id,client_secret,authorized_grant_types,scope)
values("acme","acmesecret","client_credentials","openid");
再次執行:
4:如何在運行時動態的修改客戶端
http://projects.spring.io/spring-security-oauth/docs/oauth2.html (Configuring ClientDetails)
5:如何將TOKEN存庫
http://projects.spring.io/spring-security-oauth/docs/oauth2.html(Managing Tokens)
@Configuration
@EnableResourceServer
protected static class ResourceServer extendsResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public voidconfigure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
}
@Bean
publicJdbcTokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Override
public voidconfigure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore());
}
6:如何把請求放到URL中訪問
在前面的demo中,獲取TOKEN,都是通過curl -v -X POST"acme:acmesecret@localhost:8080/oauth/token?grant_type=client_credentials"拿到的,如果使用我們熟悉的get方式 curl http://localhost:8080/uaa/oauth/token?grant_type=client_credentials&client_id=acme&client_secret=acmesecret或者post方式curl -d"grant_type=client_credentials&client_id=acme&client_secret=acmesecret"http://localhost:8080/uaa/oauth/token。會拋出一樣的錯誤提示。
修改我們上面的Oauth2Config類
重啓服務器,再次通過get,或者post提交試試.
POST請求
GET請求依然不支持
7:SCOPE的使用
我們知道,Oauth2.0中,生成TOKEN之後,就可以拿着TOKEN來訪問我受保護的resource了。但如果有個url,比如/A/B地址,我只希望指定的客戶端才能訪問,要如何操作呢。
1:數據庫對應的client
2:修改ResourceServer配置
測試:
1:使用ADMIN對應的客戶端acme進行測試
請求/uaa/oauth/token地址,獲取TOKEN
用生成的TOKEN,訪問hello
2:使用CLIENT對應的客戶端acme2進行測試
請求/uaa/oauth/token地址,獲取TOKEN
用生成的TOKEN,訪問hello
8:如何重寫ClientDetailsService
從源碼可以看到,ClientDetailsService的實現,來自於ClientDetailsServiceConfigurer的配置,而ClientDetailsServiceConfigurer只提供了inMemory和jdbc兩種方法。比如,要從遠程的restapi獲取client信息,我們可以自己實現一個ClientDetailsService,不用默認的。
9:擴展TOKEN內容
在例子8中,我們向Client中,添加了自定義的group和client。跟蹤TokenEndpoint源碼會發現,雖然OAuth2AccessToken提供了getAdditionalInformation方法,用來對Token進行擴展,但是源碼中並沒有將Client的擴展信息放入Token中,所以最終/oauth/token返回的json中,是沒有group和role信息的。跟蹤源碼,會發現生成Token是,提供了對token的擴展。
下面是接口實現
10:如何修改Header信息
默認情況,通過curl -H "Authorization:Bearer8bc6275d-ed2d-442e-b7b4-aa2fab536c4e" http://localhost:9003/uaa/v1/hello方式訪問資源
1:把/oauth/token配置到了security.ignored=/oauth/check_token,/oauth/token