首页 > 编程 > Java > 正文

Spring Cloud下基于OAUTH2认证授权的实现示例

2019-11-26 10:12:15
字体:
来源:转载
供稿:网友

Spring Cloud需要使用OAUTH2来实现多个微服务的统一认证授权,通过向OAUTH服务发送某个类型的grant type进行集中认证和授权,从而获得access_token,而这个token是受其他微服务信任的,我们在后续的访问可以通过access_token来进行,从而实现了微服务的统一认证授权。

本示例提供了四大部分:

  1. discovery-service:服务注册和发现的基本模块
  2. auth-server:OAUTH2认证授权中心
  3. order-service:普通微服务,用来验证认证和授权
  4. api-gateway:边界网关(所有微服务都在它之后)

OAUTH2中的角色:

  1. Resource Server:被授权访问的资源
  2. Authotization Server:OAUTH2认证授权中心
  3. Resource Owner: 用户
  4. Client:使用API的客户端(如Android 、IOS、web app)

Grant Type:

  1. Authorization Code:用在服务端应用之间
  2. Implicit:用在移动app或者web app(这些app是在用户的设备上的,如在手机上调起微信来进行认证授权)
  3. Resource Owner Password Credentials(password):应用直接都是受信任的(都是由一家公司开发的,本例子使用
  4. Client Credentials:用在应用API访问。

1.基础环境

使用Postgres作为账户存储,Redis作为Token存储,使用docker-compose在服务器上启动PostgresRedis

Redis: image: sameersbn/redis:latest ports: - "6379:6379" volumes: - /srv/docker/redis:/var/lib/redis:Z restart: alwaysPostgreSQL: restart: always image: sameersbn/postgresql:9.6-2 ports: - "5432:5432" environment: - DEBUG=false - DB_USER=wang - DB_PASS=yunfei - DB_NAME=order volumes: - /srv/docker/postgresql:/var/lib/postgresql:Z

2.auth-server

2.1 OAuth2服务配置

Redis用来存储token,服务重启后,无需重新获取token.

@Configuration@EnableAuthorizationServerpublic class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private RedisConnectionFactory connectionFactory; @Bean public RedisTokenStore tokenStore() {  return new RedisTokenStore(connectionFactory); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {  endpoints    .authenticationManager(authenticationManager)    .tokenStore(tokenStore()); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {  security    .tokenKeyAccess("permitAll()")    .checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {  clients.inMemory()    .withClient("android")    .scopes("xx") //此处的scopes是无用的,可以随意设置    .secret("android")    .authorizedGrantTypes("password", "authorization_code", "refresh_token")   .and()    .withClient("webapp")    .scopes("xx")    .authorizedGrantTypes("implicit"); }}

2.2 Resource服务配置

auth-server提供user信息,所以auth-server也是一个Resource Server

@Configuration@EnableResourceServerpublic class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception {  http    .csrf().disable()    .exceptionHandling()    .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))   .and()    .authorizeRequests()    .anyRequest().authenticated()   .and()    .httpBasic(); }}
@RestControllerpublic class UserController { @GetMapping("/user") public Principal user(Principal user){  return user; }}

2.3 安全配置

@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public UserDetailsService userDetailsService(){  return new DomainUserDetailsService(); } @Bean public PasswordEncoder passwordEncoder() {  return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {  auth    .userDetailsService(userDetailsService())    .passwordEncoder(passwordEncoder()); } @Bean public SecurityEvaluationContextExtension securityEvaluationContextExtension() {  return new SecurityEvaluationContextExtension(); } //不定义没有password grant_type @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception {  return super.authenticationManagerBean(); }}

2.4 权限设计

采用用户(SysUser) 角色(SysRole) 权限(SysAuthotity)设置,彼此之间的关系是多对多。通过DomainUserDetailsService 加载用户和权限。

2.5 配置

spring: profiles: active: ${SPRING_PROFILES_ACTIVE:dev} application:  name: auth-server jpa: open-in-view: true database: POSTGRESQL show-sql: true hibernate:  ddl-auto: update datasource: platform: postgres url: jdbc:postgresql://192.168.1.140:5432/auth username: wang password: yunfei driver-class-name: org.postgresql.Driver redis: host: 192.168.1.140server: port: 9999eureka: client: serviceUrl:  defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/logging.level.org.springframework.security: DEBUGlogging.leve.org.springframework: DEBUG##很重要security: oauth2: resource:  filter-order: 3

2.6 测试数据

data.sql里初始化了两个用户admin->ROLE_ADMIN->query_demo,wyf->ROLE_USER

3.order-service

3.1 Resource服务配置

@Configuration@EnableResourceServerpublic class ResourceServerConfig extends ResourceServerConfigurerAdapter{ @Override public void configure(HttpSecurity http) throws Exception {  http    .csrf().disable()    .exceptionHandling()    .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))   .and()    .authorizeRequests()    .anyRequest().authenticated()   .and()    .httpBasic(); }}

3.2 用户信息配置

order-service是一个简单的微服务,使用auth-server进行认证授权,在它的配置文件指定用户信息在auth-server的地址即可:

security: oauth2: resource:  id: order-service  user-info-uri: http://localhost:8080/uaa/user  prefer-token-info: false

3.3 权限测试控制器

具备authorityquery-demo的才能访问,即为admin用户

@RestControllerpublic class DemoController { @GetMapping("/demo") @PreAuthorize("hasAuthority('query-demo')") public String getDemo(){  return "good"; }}

4 api-gateway

api-gateway在本例中有2个作用:

  1. 本身作为一个client,使用implicit
  2. 作为外部app访问的方向代理

4.1 关闭csrf并开启Oauth2 client支持

@Configuration@EnableOAuth2Ssopublic class SecurityConfig extends WebSecurityConfigurerAdapter{ @Override protected void configure(HttpSecurity http) throws Exception {  http.csrf().disable(); }}

4.2 配置

zuul: routes: uaa:  path: /uaa/**  sensitiveHeaders:  serviceId: auth-server order:  path: /order/**  sensitiveHeaders:  serviceId: order-service add-proxy-headers: truesecurity: oauth2: client:  access-token-uri: http://localhost:8080/uaa/oauth/token  user-authorization-uri: http://localhost:8080/uaa/oauth/authorize  client-id: webapp resource:  user-info-uri: http://localhost:8080/uaa/user  prefer-token-info: false

5 演示

5.1 客户端调用

使用Postmanhttp://localhost:8080/uaa/oauth/token发送请求获得access_token(admin用户的如7f9b54d4-fd25-4a2c-a848-ddf8f119230b)

admin用户

wyf用户

5.2 api-gateway中的webapp调用

暂时没有做测试,下次补充。

6 源码地址

https://github.com/wiselyman/uaa-zuul

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表