在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 。
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: 32.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 權限測試控制器
具備authority未query-demo的才能訪問,即為admin用戶
@RestControllerpublic class DemoController { @GetMapping("/demo") @PreAuthorize("hasAuthority('query-demo')") public String getDemo(){ return "good"; }}4 api-gateway
api-gateway在本例中有2個作用:
implicit4.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 客戶端調用
使用Postman向http://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
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。