第一種配置方式: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訪問)

