OAuth2.0協議專區-SpringCloud+zuul+oauth2 實現服務統一認證


第一種配置方式:zuul只負責轉發,流控等(不負責認證)

1.介紹

(1) eureka服務發現,各服務配置就不發了,只看關於認證這塊;

2 配置認證服務器

(1)添加依賴(oauth已經包含了security)

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

(2)配置認證

@Configuration
public class MyConfig {
 
    //設置用戶信息處理類,這里為了測試使用密碼123,用戶名隨意
    @Component
    public static class MyUserDetailsService implements UserDetailsService {
        
     @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return new User(username, passwordEncoder.encode("123"), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER")); } } //認證服務器 @EnableAuthorizationServer @Configuration public static class Authorization extends AuthorizationServerConfigurerAdapter { @Autowired AuthenticationManager authenticationManager; @Autowired BCryptPasswordEncoder bCryptPasswordEncoder; @Autowired MyUserDetailsService myUserDetailsService; //為了測試客戶端與憑證存儲在內存(生產應該用數據庫來存儲,oauth有標准數據庫模板) @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client") // client_id .secret(bCryptPasswordEncoder.encode("123")) // client_secret .authorizedGrantTypes("authorization_code", "password") // 該client允許的授權類型 .scopes("app"); // 允許的授權范圍 } //authenticationManager配合password模式使用,tokenstore生產可用redis @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) .tokenStore(new InMemoryTokenStore()) .userDetailsService(myUserDetailsService); } //配置token狀態查詢 @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.tokenKeyAccess("permitAll()"); security.checkTokenAccess("isAuthenticated()"); } } //認證服務器需配合Security使用 @Configuration public static class SecurityConfig extends WebSecurityConfigurerAdapter {
     @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //這里只驗證是否帶有token的失敗返回authenticationEntryPoint @Override protected void configure(HttpSecurity http) throws Exception {   http.httpBasic().and() .csrf().disable() .exceptionHandling() .authenticationEntryPoint((req, resp, exception) -> { resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); resp.getWriter().write(new ObjectMapper().writeValueAsString(new HashMap() {{ put("status", 0); put("error", "沒有權限"); }})); }).and() .authorizeRequests().anyRequest().authenticated(); } } //配置資源處理器,為了其他客戶端訪問該登陸用戶信息等 @Configuration @EnableResourceServer public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable().exceptionHandling().authenticationEntryPoint((req, resp, exception) -> { resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); resp.getWriter().write(new ObjectMapper().writeValueAsString(new HashMap() {{ put("status", 0); put("error", "沒有權限"); }})); }).and().authorizeRequests().anyRequest().authenticated(); } } }

  

(3)提供客戶信息

@RestController
public class ResourceWeb {
 
    @GetMapping("/member")
    public Principal user(Principal member) {
        //獲取當前用戶信息
        return member;
    }
}

(4)流程

  這里用的是密碼方式,一般用於本地服務自身資源的調用;

(client,secret)代表客戶端賬號密碼,在該測試中,這個客戶端其實就表示本地的服務.如果是第三方,則申請到賬號密碼后,可以在得到用戶授權后進行資源調用;

(username,password)就是本服務的用戶主體了,所有客戶端獲取資源都需要本地用戶的登陸成功授權后方可獲取,所以用到了security的登陸策略;

3.配置資源服務器(本地資源)

(1)同樣添加oauth依賴

(2)配置遠程認證服務:

security:
  oauth2:
    resource:
      user-info-uri: http://localhost:8082/member
      prefer-token-info: false

  

@Configuration
public class MyConfig {
 
    //配置資源服務器
    @Configuration
    @EnableResourceServer
    public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().httpBasic().disable().exceptionHandling().authenticationEntryPoint((req, resp, exception) -> {
                resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                resp.getWriter().write(new ObjectMapper().writeValueAsString(new HashMap() {{
                    put("status", 0);
                    put("error", "沒有權限");
                }}));
            })
            .and().authorizeRequests().antMatchers("/noauth").permitAll()
            .and().authorizeRequests().anyRequest().authenticated();
        }
    }
}

4.配置zuul

zuul:
  #routes:
  #  MECHANT:
  #    service-id: MECHANT
  #    path: /mechant/**
  strip-prefix: true    #當為false時,請求地址->MECHANT->http://localhost:8081/api/mechant/ping,返回404
  prefix: /api          #請求前綴
  sensitive-headers:   #此處不寫則無法攜帶header;如果客戶端在發請求是帶了X-ABC,那么X-ABC不會傳遞給下游服務
  #ignoredHeaders: X-ABC    #如果客戶端在發請求是帶了X-ABC,那么X-ABC依然會傳遞給下游服務。但是如果下游服務再轉發就會被過濾

  

5.測試

(1)申請token(使用zuul訪問)

(2)使用token(使用zuul訪問)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM