Spring Cloud下基于OAUTH2认证授权的实现 博客分类: java spring
在Spring Cloud需要使用OAUTH2来实现多个微服务的统一认证授权,通过向OAUTH服务发送某个类型的grant type进行集中认证和授权,从而获得access_token,而这个token是受其他微服务信任的,我们在后续的访问可以通过access_token来进行,从而实现了微服务的统一认证授权。
本示例提供了四大部分:
discovery-service:服务注册和发现的基本模块auth-server:OAUTH2认证授权中心order-service:普通微服务,用来验证认证和授权api-gateway:边界网关(所有微服务都在它之后)
OAUTH2中的角色:
Resource Server:被授权访问的资源Authotization Server:OAUTH2认证授权中心Resource Owner: 用户Client:使用API的客户端(如Android 、IOS、web app)
Grant Type:
Authorization Code:用在服务端应用之间Implicit:用在移动app或者web app(这些app是在用户的设备上的,如在手机上调起微信来进行认证授权)Resource Owner Password Credentials(password):应用直接都是受信任的(都是由一家公司开发的,本例子使用)Client Credentials:用在应用API访问。
1.基础环境
使用Postgres作为账户存储,Redis作为Token存储,使用docker-compose在服务器上启动Postgres和Redis。
1Redis: 2 image: sameersbn/redis:latest 3 ports: 4 - "6379:6379" 5 volumes: 6 - /srv/docker/redis:/var/lib/redis:Z 7 restart: always 8 9PostgreSQL: 10 restart: always 11 image: sameersbn/postgresql:9.6-2 12 ports: 13 - "5432:5432" 14 environment: 15 - DEBUG=false 16 17 - DB_USER=wang 18 - DB_PASS=yunfei 19 - DB_NAME=order 20 volumes: 21 - /srv/docker/postgresql:/var/lib/postgresql:Z
2.auth-server
2.1 OAuth2服务配置
Redis用来存储token,服务重启后,无需重新获取token.
1@Configuration 2@EnableAuthorizationServer 3public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { 4 @Autowired 5 private AuthenticationManager authenticationManager; 6 @Autowired 7 private RedisConnectionFactory connectionFactory; 8 9 10 @Bean 11 public RedisTokenStore tokenStore() { 12 return new RedisTokenStore(connectionFactory); 13 } 14 15 16 @Override 17 public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 18 endpoints 19 .authenticationManager(authenticationManager) 20 .tokenStore(tokenStore()); 21 } 22 23 @Override 24 public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 25 security 26 .tokenKeyAccess("permitAll()") 27 .checkTokenAccess("isAuthenticated()"); 28 } 29 30 @Override 31 public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 32 clients.inMemory() 33 .withClient("android") 34 .scopes("xx") //此处的scopes是无用的,可以随意设置 35 .secret("android") 36 .authorizedGrantTypes("password", "authorization_code", "refresh_token") 37 .and() 38 .withClient("webapp") 39 .scopes("xx") 40 .authorizedGrantTypes("implicit"); 41 } 42} 43 44
2.2 Resource服务配置
auth-server提供user信息,所以auth-server也是一个Resource Server
1@Configuration 2@EnableResourceServer 3public class ResourceServerConfig extends ResourceServerConfigurerAdapter { 4 5 @Override 6 public void configure(HttpSecurity http) throws Exception { 7 http 8 .csrf().disable() 9 .exceptionHandling() 10 .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED)) 11 .and() 12 .authorizeRequests() 13 .anyRequest().authenticated() 14 .and() 15 .httpBasic(); 16 } 17} 18 19 20 21@RestController 22public class UserController { 23 24 @GetMapping("/user") 25 public Principal user(Principal user){ 26 return user; 27 } 28} 29
2.3 安全配置
1@Configuration 2public class SecurityConfig extends WebSecurityConfigurerAdapter { 3 4 5 6 @Bean 7 public UserDetailsService userDetailsService(){ 8 return new DomainUserDetailsService(); 9 } 10 11 @Bean 12 public PasswordEncoder passwordEncoder() { 13 return new BCryptPasswordEncoder(); 14 } 15 16 @Override 17 protected void configure(AuthenticationManagerBuilder auth) throws Exception { 18 auth 19 .userDetailsService(userDetailsService()) 20 .passwordEncoder(passwordEncoder()); 21 } 22 23 @Bean 24 public SecurityEvaluationContextExtension securityEvaluationContextExtension() { 25 return new SecurityEvaluationContextExtension(); 26 } 27 28 //不定义没有password grant_type 29 @Override 30 @Bean 31 public AuthenticationManager authenticationManagerBean() throws Exception { 32 return super.authenticationManagerBean(); 33 } 34 35 36 37}
2.4 权限设计
采用用户(SysUser) 角色(SysRole) 权限(SysAuthotity)设置,彼此之间的关系是多对多。通过DomainUserDetailsService 加载用户和权限。
2.5 配置
1spring: 2 profiles: 3 active: ${SPRING_PROFILES_ACTIVE:dev} 4 application: 5 name: auth-server 6 7 jpa: 8 open-in-view: true 9 database: POSTGRESQL 10 show-sql: true 11 hibernate: 12 ddl-auto: update 13 datasource: 14 platform: postgres 15 url: jdbc:postgresql://192.168.1.140:5432/auth 16 username: wang 17 password: yunfei 18 driver-class-name: org.postgresql.Driver 19 redis: 20 host: 192.168.1.140 21 22server: 23 port: 9999 24 25 26eureka: 27 client: 28 serviceUrl: 29 defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ 30 31 32 33logging.level.org.springframework.security: DEBUG 34 35logging.leve.org.springframework: DEBUG 36 37##很重要 38security: 39 oauth2: 40 resource: 41 filter-order: 3
2.6 测试数据
data.sql里初始化了两个用户admin->ROLE_ADMIN->query_demo,wyf->ROLE_USER
3.order-service
3.1 Resource服务配置
1@Configuration 2@EnableResourceServer 3public class ResourceServerConfig extends ResourceServerConfigurerAdapter{ 4 5 @Override 6 public void configure(HttpSecurity http) throws Exception { 7 http 8 .csrf().disable() 9 .exceptionHandling() 10 .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED)) 11 .and() 12 .authorizeRequests() 13 .anyRequest().authenticated() 14 .and() 15 .httpBasic(); 16 } 17} 18
3.2 用户信息配置
order-service是一个简单的微服务,使用auth-server进行认证授权,在它的配置文件指定用户信息在auth-server的地址即可:
1security: 2 oauth2: 3 resource: 4 id: order-service 5 user-info-uri: http://localhost:8080/uaa/user 6 prefer-token-info: false
3.3 权限测试控制器
具备authority未query-demo的才能访问,即为admin用户
1@RestController 2public class DemoController { 3 @GetMapping("/demo") 4 @PreAuthorize("hasAuthority('query-demo')") 5 public String getDemo(){ 6 return "good"; 7 } 8} 9
4 api-gateway
api-gateway在本例中有2个作用:
-
本身作为一个client,使用
implicit -
作为外部app访问的方向代理
4.1 关闭csrf并开启Oauth2 client支持
1@Configuration 2@EnableOAuth2Sso 3public class SecurityConfig extends WebSecurityConfigurerAdapter{ 4 @Override 5 protected void configure(HttpSecurity http) throws Exception { 6 7 http.csrf().disable(); 8 9 } 10 11}
4.2 配置
1zuul: 2 routes: 3 uaa: 4 path: /uaa/** 5 sensitiveHeaders: 6 serviceId: auth-server 7 order: 8 path: /order/** 9 sensitiveHeaders: 10 serviceId: order-service 11 add-proxy-headers: true 12 13security: 14 oauth2: 15 client: 16 access-token-uri: http://localhost:8080/uaa/oauth/token 17 user-authorization-uri: http://localhost:8080/uaa/oauth/authorize 18 client-id: webapp 19 resource: 20 user-info-uri: http://localhost:8080/uaa/user 21 prefer-token-info: false
5 演示
5.1 客户端调用
使用Postman向http://localhost:8080/uaa/oauth/token发送请求获得access_token(admin用户的如7f9b54d4-fd25-4a2c-a848-ddf8f119230b)
-
admin用户



-
wyf用户



5.2 api-gateway中的webapp调用
暂时没有做测试,下次补充。
http://www.wisely.top/2017/06/14/spring-cloud-oauth2-zuul/