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