框架使用SpringBoot + Spring Security Oauth2
主要完成了客户端授权
可以通过mysql数据库读取当前客户端表信息进行验证,token存储在数据库中
1.引入依赖
oauth2 依赖于spring security,需要引入spring, mysql,redis, mybatis
<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></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
2. 配置文件
server:port: 8081spring:datasource:url: jdbc:mysql://127.0.0.1:3306/oauth2?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverredis:host: 127.0.0.1database: 0mybatis:mapper-locations: mapper/*.xmlsecurity:oauth2:resource:filter-order: 3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
3. 配置
关于oauth2协议相关内容以及授权流程 查看别的博文
主要会使用3个类来配置
- AuthorizationServerConfiguration 授权验证配置
继承AuthorizationServerConfigurerAdapter,配置授权的相关信息,配置的核心都在这里
在这里进行 配置客户端,配置token存储方式等
package oauth.security.client.configauto;import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import oauth.security.client.configauto.jdbcdetail.MyJdbcTokenStore;@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {private static final String DEMO_RESOURCE_ID = "*";@AutowiredAuthenticationManager authenticationManager;@AutowiredRedisConnectionFactory redisConnectionFactory;@Autowiredprivate DataSource dataSource;// 初始化JdbcTokenStore@Autowiredpublic TokenStore getTokenStore() {return new JdbcTokenStore(dataSource);}// 自定义数据库存储tokenStore@Autowiredpublic TokenStore getMyTokenStore() {return new MyJdbcTokenStore(dataSource);}@Autowiredprivate TokenStore getRedisTokenStore() {return new RedisTokenStore(redisConnectionFactory);}@Bean // 声明ApplyClientDetailServicepublic ApplyClientDetailService getClientDetails() {return new ApplyClientDetailService();}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {// 配置客户端, 用于client认证clients.withClientDetails(getClientDetails());
/* //使用存在内存中配置clients.inMemory().withClient("client_1").resourceIds(DEMO_RESOURCE_ID).authorizedGrantTypes("client_credentials", "refresh_token").scopes("all").authorities("client").secret("123456");*/}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory)).authenticationManager(authenticationManager); // redis保存token
/* endpoints.tokenStore(getTokenStore()) // 数据库保存token.authenticationManager(authenticationManager);*/}@Overridepublic void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {//允许表单认证oauthServer.allowFormAuthenticationForClients();}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
在配置客户端中,使用了ApplyClientDetailService类,是自定义的获取Client的一个类,继承ClientDetailsService
对Client的访问主要依靠JdbcClientDetailsService类的实现,必须使用官方给出的数据库结构,如果想自定义数据库结构,可以根据需求重写JdbcClientDetailsService类的实现。
package oauth.security.client.configauto;import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import oauth.security.client.service.ApplyService;public class ApplyClientDetailService implements ClientDetailsService {@Autowiredprivate ApplyService applyService;@Autowiredprivate DataSource dataSource;@Overridepublic ClientDetails loadClientByClientId(String applyName) throws ClientRegistrationException {/*// 使用mybatic验证client是否存在 ,根据需求写sqlMap clientMap = applyService.findApplyById(applyName);if(clientMap == null) {throw new ClientRegistrationException("应用" + applyName + "不存在!");}*/// MyJdbcClientDetailsService jdbcClientDetailsService= new MyJdbcClientDetailsService(dataSource, "authentication");JdbcClientDetailsService jdbcClientDetailsService= new JdbcClientDetailsService(dataSource);ClientDetails clientDetails = jdbcClientDetailsService.loadClientByClientId(applyName);return clientDetails;}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- ResourceServerConfiguration 资源配置
配置了资源权限
package oauth.security.client.configauto;import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {private static final String DEMO_RESOURCE_ID = "*";@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.resourceId(DEMO_RESOURCE_ID).stateless(true);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().requestMatchers().anyRequest().and().anonymous().and().authorizeRequests()
// .antMatchers("/product/**").access("#oauth2.hasScope('select') and hasRole('ROLE_USER')").antMatchers("/**").authenticated(); //配置访问权限控制,必须认证过后才可以访问}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- SecurityConfiguration 安全配置
package oauth.security.client.configauto;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;/*** Created by fcz on 2017/12/28.*/
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Autowiredprivate ClientDetailsService clientDetailsService;@Autowiredprivate RedisConnectionFactory redisConnection;@Bean // 声明ApplyClientDetailServicepublic ApplyClientDetailService getClientDetails() {return new ApplyClientDetailService();}@Bean@Overrideprotected UserDetailsService userDetailsService(){InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();manager.createUser(User.withUsername("user_1").password("123456").authorities("USER").build());manager.createUser(User.withUsername("user_2").password("123456").authorities("USER").build());return manager;}@Beanpublic TokenStore tokenStore() {return new RedisTokenStore(redisConnection);}@Bean@Autowiredpublic TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();handler.setTokenStore(tokenStore());handler.setRequestFactory(new DefaultOAuth2RequestFactory(getClientDetails()));handler.setClientDetailsService(getClientDetails());return handler;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.requestMatchers().anyRequest().and().authorizeRequests().antMatchers("/oauth/*").permitAll();}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
接口访问
使用postMan访问
客户端请求token,POST :http://localhost:8081/oauth/token?grant_type=client_credentials&scope=all&client_id=apply&client_secret=123456
用户请求token,POST :http://localhost:8081/oauth/token?grant_type=password&username=user_1&password=123456&scope=all&client_id=apply&client_secret=123456
详细代码在githup : SpringSecurityOauth2