├── .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 | ![oauth2](http://img.blog.csdn.net/20160914172241289) 178 | 179 | 画风虽然很简陋,但是基本功能都具备了。点击`Authorize`后,浏览器就会重定向到百度,并带上`code`参数: 180 | 181 | ![这里写图片描述](http://img.blog.csdn.net/20160914172412190) 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 | ![这里写图片描述](http://img.blog.csdn.net/20160914174747955) 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!

--------------------------------------------------------------------------------