├── .gitignore
├── README.md
├── pom.xml
└── src
└── main
├── java
└── cn
│ └── com
│ └── sina
│ └── alan
│ └── oauth
│ ├── AlanOAuthApplication.java
│ ├── config
│ ├── AlanOAuthWebConfig.java
│ └── OAuthSecurityConfig.java
│ ├── controller
│ └── ErrorCtr.java
│ └── security
│ └── AlanSsoAuthProvider.java
└── resources
├── application.properties
└── templates
└── error.vm
/.gitignore:
--------------------------------------------------------------------------------
1 | # maven ignore
2 | target/
3 | *.jar
4 | *.war
5 | *.zip
6 | *.tar
7 | *.tar.gz
8 |
9 | # eclipse ignore
10 | .settings/
11 | .project
12 | .classpath
13 |
14 | # idea ignore
15 | .idea/
16 | *.ipr
17 | *.iml
18 | *.iws
19 | *.springBeans
20 |
21 | # temp ignore
22 | *.log
23 | *.cache
24 | *.diff
25 | *.patch
26 | *.tmp
27 | *.java~
28 | *.properties~
29 | *.xml~
30 | *.bak
31 |
32 | # system ignore
33 | .DS_Store
34 | Thumbs.db
35 |
36 | *.log
37 |
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring Security OAuth2 Demo
2 | 项目使用的是MySql存储, 需要先创建以下表结构:
3 | ```
4 |
5 | CREATE SCHEMA IF NOT EXISTS `alan-oauth` DEFAULT CHARACTER SET utf8 ;
6 | USE `alan-oauth` ;
7 |
8 | -- -----------------------------------------------------
9 | -- Table `alan-oauth`.`clientdetails`
10 | -- -----------------------------------------------------
11 | CREATE TABLE IF NOT EXISTS `alan-oauth`.`clientdetails` (
12 | `appId` VARCHAR(128) NOT NULL,
13 | `resourceIds` VARCHAR(256) NULL DEFAULT NULL,
14 | `appSecret` VARCHAR(256) NULL DEFAULT NULL,
15 | `scope` VARCHAR(256) NULL DEFAULT NULL,
16 | `grantTypes` VARCHAR(256) NULL DEFAULT NULL,
17 | `redirectUrl` VARCHAR(256) NULL DEFAULT NULL,
18 | `authorities` VARCHAR(256) NULL DEFAULT NULL,
19 | `access_token_validity` INT(11) NULL DEFAULT NULL,
20 | `refresh_token_validity` INT(11) NULL DEFAULT NULL,
21 | `additionalInformation` VARCHAR(4096) NULL DEFAULT NULL,
22 | `autoApproveScopes` VARCHAR(256) NULL DEFAULT NULL,
23 | PRIMARY KEY (`appId`))
24 | ENGINE = InnoDB
25 | DEFAULT CHARACTER SET = utf8;
26 |
27 |
28 | -- -----------------------------------------------------
29 | -- Table `alan-oauth`.`oauth_access_token`
30 | -- -----------------------------------------------------
31 | CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_access_token` (
32 | `token_id` VARCHAR(256) NULL DEFAULT NULL,
33 | `token` BLOB NULL DEFAULT NULL,
34 | `authentication_id` VARCHAR(128) NOT NULL,
35 | `user_name` VARCHAR(256) NULL DEFAULT NULL,
36 | `client_id` VARCHAR(256) NULL DEFAULT NULL,
37 | `authentication` BLOB NULL DEFAULT NULL,
38 | `refresh_token` VARCHAR(256) NULL DEFAULT NULL,
39 | PRIMARY KEY (`authentication_id`))
40 | ENGINE = InnoDB
41 | DEFAULT CHARACTER SET = utf8;
42 |
43 |
44 | -- -----------------------------------------------------
45 | -- Table `alan-oauth`.`oauth_approvals`
46 | -- -----------------------------------------------------
47 | CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_approvals` (
48 | `userId` VARCHAR(256) NULL DEFAULT NULL,
49 | `clientId` VARCHAR(256) NULL DEFAULT NULL,
50 | `scope` VARCHAR(256) NULL DEFAULT NULL,
51 | `status` VARCHAR(10) NULL DEFAULT NULL,
52 | `expiresAt` DATETIME NULL DEFAULT NULL,
53 | `lastModifiedAt` DATETIME NULL DEFAULT NULL)
54 | ENGINE = InnoDB
55 | DEFAULT CHARACTER SET = utf8;
56 |
57 |
58 | -- -----------------------------------------------------
59 | -- Table `alan-oauth`.`oauth_client_details`
60 | -- -----------------------------------------------------
61 | CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_client_details` (
62 | `client_id` VARCHAR(128) NOT NULL,
63 | `resource_ids` VARCHAR(256) NULL DEFAULT NULL,
64 | `client_secret` VARCHAR(256) NULL DEFAULT NULL,
65 | `scope` VARCHAR(256) NULL DEFAULT NULL,
66 | `authorized_grant_types` VARCHAR(256) NULL DEFAULT NULL,
67 | `web_server_redirect_uri` VARCHAR(256) NULL DEFAULT NULL,
68 | `authorities` VARCHAR(256) NULL DEFAULT NULL,
69 | `access_token_validity` INT(11) NULL DEFAULT NULL,
70 | `refresh_token_validity` INT(11) NULL DEFAULT NULL,
71 | `additional_information` VARCHAR(4096) NULL DEFAULT NULL,
72 | `autoapprove` VARCHAR(256) NULL DEFAULT NULL,
73 | PRIMARY KEY (`client_id`))
74 | ENGINE = InnoDB
75 | DEFAULT CHARACTER SET = utf8;
76 |
77 |
78 | -- -----------------------------------------------------
79 | -- Table `alan-oauth`.`oauth_client_token`
80 | -- -----------------------------------------------------
81 | CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_client_token` (
82 | `token_id` VARCHAR(256) NULL DEFAULT NULL,
83 | `token` BLOB NULL DEFAULT NULL,
84 | `authentication_id` VARCHAR(128) NOT NULL,
85 | `user_name` VARCHAR(256) NULL DEFAULT NULL,
86 | `client_id` VARCHAR(256) NULL DEFAULT NULL,
87 | PRIMARY KEY (`authentication_id`))
88 | ENGINE = InnoDB
89 | DEFAULT CHARACTER SET = utf8;
90 |
91 |
92 | -- -----------------------------------------------------
93 | -- Table `alan-oauth`.`oauth_code`
94 | -- -----------------------------------------------------
95 | CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_code` (
96 | `code` VARCHAR(256) NULL DEFAULT NULL,
97 | `authentication` BLOB NULL DEFAULT NULL)
98 | ENGINE = InnoDB
99 | DEFAULT CHARACTER SET = utf8;
100 |
101 |
102 | -- -----------------------------------------------------
103 | -- Table `alan-oauth`.`oauth_refresh_token`
104 | -- -----------------------------------------------------
105 | CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_refresh_token` (
106 | `token_id` VARCHAR(256) NULL DEFAULT NULL,
107 | `token` BLOB NULL DEFAULT NULL,
108 | `authentication` BLOB NULL DEFAULT NULL)
109 | ENGINE = InnoDB
110 | DEFAULT CHARACTER SET = utf8;
111 |
112 | ```
113 | 然后在`oauth_client_details`表中插入记录:
114 | ```
115 | # client_id, resource_ids, client_secret, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove
116 | 'client', NULL, 'secret', 'app', 'authorization_code', 'http://www.baidu.com', NULL, NULL, NULL, NULL, NULL
117 | ```
118 | 这时就可以访问授权页面了:
119 | ```
120 | localhost:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com
121 | ```
122 | 访问时Spring让你登陆,随便输入一个用户名密码即可。
123 | **注意, 如果每次登陆时输入的用户名不一样,那么Spring Security会认为是不同的用户,因此访问/token/authorize会再次显示授权页面。如果用户名一致, 则只需要授权一次**
124 |
125 | 数据库连接信息在`application.properties`中配置。
126 |
127 |
128 | Spring Cloud Security OAuth2 是 Spring 对 OAuth2 的开源实现,优点是能与Spring Cloud技术栈无缝集成,如果全部使用默认配置,开发者只需要添加注解就能完成 OAuth2 授权服务的搭建。
129 |
130 |
131 | # 博文
132 | ## 1. 添加依赖
133 | 授权服务是基于Spring Security的,因此需要在项目中引入两个依赖:
134 | ```
135 |
136 | org.springframework.cloud
137 | spring-cloud-starter-security
138 |
139 |
140 |
141 | org.springframework.cloud
142 | spring-cloud-starter-oauth2
143 |
144 | ```
145 | 前者为 Security,后者为Security的OAuth2扩展。
146 |
147 | ## 2. 添加注解和配置
148 | 在启动类中添加`@EnableAuthorizationServer`注解:
149 | ```
150 | @SpringBootApplication
151 | @EnableAuthorizationServer
152 | public class AlanOAuthApplication {
153 | public static void main(String[] args) {
154 | SpringApplication.run(AlanOAuthApplication.class, args);
155 | }
156 | }
157 | ```
158 | 完成这些我们的授权服务最基本的骨架就已经搭建完成了。但是要想跑通整个流程,我们必须分配 `client_id`, `client_secret`才行。Spring Security OAuth2的配置方法是编写`@Configuration`类继承`AuthorizationServerConfigurerAdapter`,然后重写`void configure(ClientDetailsServiceConfigurer clients)`方法,如:
159 | ```java
160 | @Override
161 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
162 | clients.inMemory() // 使用in-memory存储
163 | .withClient("client") // client_id
164 | .secret("secret") // client_secret
165 | .authorizedGrantTypes("authorization_code") // 该client允许的授权类型
166 | .scopes("app"); // 允许的授权范围
167 | }
168 | ```
169 |
170 | ## 3. 授权流程
171 | 访问授权页面:
172 | ```
173 | localhost:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com
174 | ```
175 | 此时浏览器会让你输入用户名密码,这是因为 Spring Security 在默认情况下会对所有URL添加Basic Auth认证。默认的用户名为`user`, 密码是随机生成的,在控制台日志中可以看到。
176 |
177 | 
178 |
179 | 画风虽然很简陋,但是基本功能都具备了。点击`Authorize`后,浏览器就会重定向到百度,并带上`code`参数:
180 |
181 | 
182 |
183 | 拿到`code`以后,就可以调用
184 | ```
185 | POST/GET http://client:secret@localhost:8080/oauth/token
186 | ```
187 | 来换取`access_token`了:
188 | ```
189 | curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'grant_type=authorization_code&code=Li4NZo&redirect_uri=http://www.baidu.com' "http://client:secret@localhost:8080/oauth/token"
190 | ```
191 | > 注意,URL中的client为上文中通过`ClientDetailsServiceConfigurer`类指定的clientId。由于authorization_code的授权方式不需要 client_secret, 因此secret可以填写任意值
192 |
193 | 返回如下:
194 | ```json
195 | {
196 | "access_token": "32a1ca28-bc7a-4147-88a1-c95abcc30556", // 令牌
197 | "token_type": "bearer",
198 | "expires_in": 2591999,
199 | "scope": "app"
200 | }
201 | ```
202 | 到此我们最最基本的授权服务就搭建完成了。然而,这仅仅是个demo,如果要在生产环境中使用,还需要做更多的工作。
203 |
204 | ## 4. 使用MySQL存储access_token和client信息
205 | 在上面的例子中,所有的token信息都是保存在内存中的,这显然无法在生产环境中使用(进程结束后所有token丢失, 用户需要重新授权),因此我们需要将这些信息进行持久化操作。
206 | 把授权服务器中的数据存储到数据库中并不难,因为 Spring Cloud Security OAuth 已经为我们设计好了一套Schema和对应的DAO对象。但在使用之前,我们需要先对相关的类有一定的了解。
207 |
208 | ### 4.1 相关接口
209 | Spring Cloud Security OAuth2通过`DefaultTokenServices`类来完成token生成、过期等 OAuth2 标准规定的业务逻辑,而`DefaultTokenServices`又是通过`TokenStore`接口完成对生成数据的持久化。在上面的demo中,`TokenStore`的默认实现为`InMemoryTokenStore`,即内存存储。 对于Client信息,`ClientDetailsService`接口负责从存储仓库中读取数据,在上面的demo中默认使用的也是`InMemoryClientDetialsService`实现类。说到这里就能看出,要想使用数据库存储,只需要提供这些接口的实现类即可。庆幸的是,框架已经为我们写好JDBC实现了,即`JdbcTokenStore`和`JdbcClientDetailsService`。
210 |
211 | ### 4.2 建表
212 | 要想使用这些JDBC实现,首先要建表。框架为我们提前设计好了schema, 在github上:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
213 |
214 | 在使用这套表结构之前要注意的是,对于MySQL来说,默认建表语句中主键是varchar(255)类型,在mysql中执行会报错,原因是mysql对varchar主键长度有限制。所以这里改成128即可。其次,语句中会有某些字段为`LONGVARBINARY`类型,它对应mysql的`blob`类型,也需要修改一下。
215 |
216 | ### 4.3 配置
217 | 数据库建好后,下一步就是配置框架使用JDBC实现。方法还是编写`@Configuration`类继承`AuthorizationServerConfigurerAdapter`:
218 | ```
219 | @Autowired
220 | private AuthenticationManager authenticationManager;
221 |
222 | @Autowired
223 | private DataSource dataSource;
224 | @Bean // 声明TokenStore实现
225 | public TokenStore tokenStore() {
226 | return new JdbcTokenStore(dataSource);
227 | }
228 | @Bean // 声明 ClientDetails实现
229 | public ClientDetailsService clientDetails() {
230 | return new JdbcClientDetailsService(dataSource);
231 | }
232 | @Override // 配置框架应用上述实现
233 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
234 | endpoints.authenticationManager(authenticationManager);
235 | endpoints.tokenStore(tokenStore());
236 |
237 | // 配置TokenServices参数
238 | DefaultTokenServices tokenServices = new DefaultTokenServices();
239 | tokenServices.setTokenStore(endpoints.getTokenStore());
240 | tokenServices.setSupportRefreshToken(false);
241 | tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
242 | tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
243 | tokenServices.setAccessTokenValiditySeconds( (int) TimeUnit.DAYS.toSeconds(30)); // 30天
244 | endpoints.tokenServices(tokenServices);
245 | }
246 | ```
247 | 完成这些后,框架就会将中间产生的数据写到mysql中了。`oauth_client_details`是client表,可以直接在该表中添加记录来添加client:
248 | 
249 |
250 | ### 4.4 需要注意的地方
251 | 这里不得不说 Spring 设计有一个奇葩地的方。注意看`oauth_access_token`表是存放访问令牌的,但是并没有直接在字段中存放token。Spring 使用`OAuth2AccessToken`来抽象与令牌有关的所有属性,在写入到数据库时,**Spring将该对象通过JDK自带的序列化机制序列成字节** 直接保存到了该表的`token`字段中。也就是说,如果只看数据表你是看不出`access_token`的值是多少,过期时间等信息的。这就给资源服务器的实现带来了麻烦。我们的资源提供方并没有使用Spring Security,也不想引入 Spring Security 的任何依赖,这时候就只能将 `DefaultOAuth2AccessToken`的源码copy到资源提供方的项目中,然后读取`token`字段并反序列化还原对象来获取token信息。但是如果这样做还会遇到反序列化兼容性的问题,具体解决方法参考我另一篇博文: http://blog.csdn.net/neosmith/article/details/52539614
252 |
253 | ## 5. 总结
254 | 至此一个能在生产环境下使用的授权服务就搭建好了。其实我们在实际使用时应该适当定制`JdbcTokenStore`或`ClientDetailsService`来实适应业务需要,甚至可以直接从0开始实现接口,完全不用框架提供的实现。另外,Spring 直接将`DefaultOAuth2AccessToken`序列化成字节保存到数据库中的设计,我认为是非常不合理的。或许设计者的初衷是保密`access_token`,但是通过加密的方法也可以实现,完全不应该直接扔字节。不过通过定制`TokenStore`接口,我们可以使用自己的表结构而不拘泥于默认实现。
255 |
256 | ## 6. 个人看法
257 | Spring的OAuth2实现有些过于复杂了,oauth2本身只是个非常简单的协议,完全可以自己在SpringMVC的基础上自由实现,没有难度,也不复杂。我想很多人去用框架应该是担心oauth2协议复杂实现起来健壮性不足,其实是多虑了。如果是开发我个人的项目,我肯定会不使用任何框架。
258 |
259 | ---
260 | github地址: https://github.com/wanghongfei/spring-security-oauth2-example
261 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | cn.com.sina
8 | oauth-server
9 | 1.0-SNAPSHOT
10 |
11 |
12 | org.springframework.boot
13 | spring-boot-starter-parent
14 | 1.3.7.RELEASE
15 |
16 |
17 |
18 |
19 | org.springframework.cloud
20 | spring-cloud-dependencies
21 | Brixton.SR5
22 | pom
23 | import
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | org.springframework.cloud
32 | spring-cloud-starter-security
33 |
34 |
35 |
36 | org.springframework.cloud
37 | spring-cloud-starter-oauth2
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-velocity
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-jdbc
48 |
49 |
50 |
51 | mysql
52 | mysql-connector-java
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | org.apache.maven.plugins
62 | maven-compiler-plugin
63 |
64 | 1.8
65 | 1.8
66 |
67 |
68 |
69 |
70 |
71 | org.springframework.boot
72 | spring-boot-maven-plugin
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/main/java/cn/com/sina/alan/oauth/AlanOAuthApplication.java:
--------------------------------------------------------------------------------
1 | package cn.com.sina.alan.oauth;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.security.authentication.AuthenticationManager;
8 | import org.springframework.security.authentication.AuthenticationProvider;
9 | import org.springframework.security.authentication.ProviderManager;
10 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
11 | import java.util.Arrays;
12 |
13 | /**
14 | * Created by wanghongfei(hongfei7@staff.sina.com.cn) on 9/9/16.
15 | */
16 | @SpringBootApplication
17 | @EnableAuthorizationServer
18 | public class AlanOAuthApplication {
19 | public static void main(String[] args) {
20 | SpringApplication.run(AlanOAuthApplication.class, args);
21 | }
22 |
23 |
24 | @Autowired
25 | private AuthenticationProvider authenticationProvider;
26 |
27 | @Bean
28 | public AuthenticationManager authenticationManager() {
29 | return new ProviderManager(Arrays.asList(authenticationProvider));
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/cn/com/sina/alan/oauth/config/AlanOAuthWebConfig.java:
--------------------------------------------------------------------------------
1 | package cn.com.sina.alan.oauth.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5 | import org.springframework.security.config.annotation.web.builders.WebSecurity;
6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
7 |
8 |
9 | /**
10 | * Created by wanghongfei(hongfei7@staff.sina.com.cn) on 9/12/16.
11 | */
12 | @Configuration
13 | public class AlanOAuthWebConfig extends WebSecurityConfigurerAdapter {
14 |
15 |
16 |
17 | @Override
18 | protected void configure(HttpSecurity http) throws Exception {
19 | super.configure(http);
20 | }
21 |
22 | @Override
23 | public void configure(WebSecurity web) throws Exception {
24 | web.ignoring()
25 | .antMatchers("/favor.ico");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/cn/com/sina/alan/oauth/config/OAuthSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package cn.com.sina.alan.oauth.config;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.security.authentication.AuthenticationManager;
7 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
8 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
9 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
10 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
11 | import org.springframework.security.oauth2.provider.ClientDetailsService;
12 | import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
13 | import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
14 | import org.springframework.security.oauth2.provider.token.TokenStore;
15 | import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.concurrent.TimeUnit;
19 |
20 |
21 | /**
22 | * Created by wanghongfei(hongfei7@staff.sina.com.cn) on 9/12/16.
23 | */
24 | @Configuration
25 | public class OAuthSecurityConfig extends AuthorizationServerConfigurerAdapter {
26 | @Autowired
27 | private AuthenticationManager authenticationManager;
28 |
29 | @Autowired
30 | private DataSource dataSource;
31 |
32 | @Bean
33 | public TokenStore tokenStore() {
34 | return new JdbcTokenStore(dataSource);
35 | }
36 |
37 |
38 | @Override
39 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
40 | endpoints.authenticationManager(authenticationManager);
41 | endpoints.tokenStore(tokenStore());
42 |
43 | // 配置TokenServices参数
44 | DefaultTokenServices tokenServices = new DefaultTokenServices();
45 | tokenServices.setTokenStore(endpoints.getTokenStore());
46 | tokenServices.setSupportRefreshToken(false);
47 | tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
48 | tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
49 | tokenServices.setAccessTokenValiditySeconds( (int) TimeUnit.DAYS.toSeconds(30)); // 30天
50 | endpoints.tokenServices(tokenServices);
51 |
52 | }
53 |
54 |
55 | @Override
56 | public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
57 | //oauthServer.checkTokenAccess("isAuthenticated()");
58 | oauthServer.checkTokenAccess("permitAll()");
59 | oauthServer.allowFormAuthenticationForClients();
60 | }
61 |
62 | @Bean
63 | public ClientDetailsService clientDetails() {
64 | return new JdbcClientDetailsService(dataSource);
65 | }
66 |
67 | @Override
68 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
69 | clients.withClientDetails(clientDetails());
70 | /* clients.inMemory()
71 | .withClient("client")
72 | .secret("secret")
73 | .authorizedGrantTypes("authorization_code")
74 | .scopes("app");*/
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/cn/com/sina/alan/oauth/controller/ErrorCtr.java:
--------------------------------------------------------------------------------
1 | package cn.com.sina.alan.oauth.controller;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.stereotype.Controller;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 | import org.springframework.web.bind.annotation.RequestParam;
8 | import org.springframework.web.bind.annotation.SessionAttributes;
9 |
10 | import java.util.Map;
11 |
12 | /**
13 | * Created by wanghongfei(hongfei7@staff.sina.com.cn) on 9/24/16.
14 | */
15 | @Controller
16 | @SessionAttributes("authorizationRequest")
17 | public class ErrorCtr {
18 | private static final Logger log = LoggerFactory.getLogger(ErrorCtr.class);
19 |
20 | @RequestMapping("/oauth/error")
21 | public String error(@RequestParam Map parameters) {
22 | String uri = parameters.get("redirect_uri");
23 | log.info("重定向: {}", uri);
24 |
25 | return "redirect:" + uri + "?error=1";
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/cn/com/sina/alan/oauth/security/AlanSsoAuthProvider.java:
--------------------------------------------------------------------------------
1 | package cn.com.sina.alan.oauth.security;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.security.authentication.AuthenticationProvider;
6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
7 | import org.springframework.security.core.Authentication;
8 | import org.springframework.security.core.AuthenticationException;
9 | import org.springframework.security.core.GrantedAuthority;
10 | import org.springframework.stereotype.Component;
11 |
12 | import java.util.Collections;
13 |
14 | /**
15 | * Created by wanghongfei(hongfei7@staff.sina.com.cn) on 9/11/16.
16 | */
17 | @Component
18 | public class AlanSsoAuthProvider implements AuthenticationProvider {
19 | private static final Logger log = LoggerFactory.getLogger(AlanSsoAuthProvider.class);
20 |
21 | @Override
22 | public Authentication authenticate(Authentication authentication) throws AuthenticationException {
23 | log.debug("自定义provider调用");
24 |
25 | // 返回一个Token对象表示登陆成功
26 | return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), Collections.emptyList());
27 | }
28 |
29 | @Override
30 | public boolean supports(Class> aClass) {
31 | return true;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | security.basic.enabled=false
2 |
3 |
4 | server.session.timeout=300
5 |
6 |
7 | spring.datasource.url=jdbc:mysql://127.0.0.1:3306/alan-oauth?characterEncoding=UTF-8
8 | spring.datasource.username=root
9 | spring.datasource.password=987654
10 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver
11 |
12 | spring.datasource.max-idle=5
13 | spring.datasource.max-wait=10000
14 | spring.datasource.min-idle=2
15 | spring.datasource.initial-size=3
16 | spring.datasource.validation-query=SELECT 1
17 | #spring.datasource.test-on-borrow=true
18 | #spring.datasource.test-while-idle=true
19 | spring.datasource.time-between-eviction-runs-millis=18800
20 | spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=50)
21 |
22 |
--------------------------------------------------------------------------------
/src/main/resources/templates/error.vm:
--------------------------------------------------------------------------------
1 | invalid parameter!
--------------------------------------------------------------------------------