接着上一篇博客:https://www.cnblogs.com/wwjj4811/p/14504825.html
概述
資源服務器實際上就是對系統功能的增刪改查,比如:商品管理、訂單管理等資源,而在微服務架構中,而這每個資源實際上就是每一個微服務。當用戶請求某個微服務資源時,首先通過認證服務器進行認證與授權,通過后再才可訪問到對應資源。
實現的功能:
- 要讓他知道自己是資源服務器,系統知道這件事后,才會在前邊加一個過濾器去驗令牌(配置@EnableResourceServer 配置類)
- 要讓他知道自己是什么資源服務器(配置資源服務器ID) ,配置去哪里驗令牌,怎么驗令牌,要帶什么信息去驗
- 進行資源的安全配置,讓系統知道資源的每個訪問權限是什么
創建商品資源模塊
模塊名:cloud-oauth2-resource-product
依賴
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-oauth2-parent</artifactId>
<groupId>com.wj</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-oauth2-resource-product</artifactId>
<dependencies>
<dependency>
<groupId>com.wj</groupId>
<artifactId>cloud-oauth2-base</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security、OAuth2 和JWT等 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<!-- 注冊到 Eureka
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
創建啟動類
啟動類com.wj.oauth2.ProductApplication
@SpringBootApplication
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
}
創建訪問資源
com.wj.oauth2.web.controller.ProductController
@RestController
@RequestMapping("/product")
public class ProductController {
@GetMapping("/list")
@PreAuthorize("hasAuthority('product:list')")
public R list() {
List<String> list = new ArrayList<>();
list.add("huawei");
list.add("vivo");
list.add("oppo");
return R.ok(list);
}
}
配置資源服務器
創建com.wj.oauth2.resource.ResourceServerConfig類,繼承ResourceServerConfigurerAdapter類
@Configuration
// 標識為資源服務器, 所有發往當前服務的請求,都會去請求頭里找token,找不到或驗證不通過不允許訪問
@EnableResourceServer
//開啟方法級別權限控制
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
//配置當前資源服務器的ID
private static final String RESOURCE_ID = "product-server";
/**當前資源服務器的一些配置, 如資源服務器ID **/
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
// 配置當前資源服務器的ID, 會在認證服務器驗證(客戶端表的resources配置了就可以訪問這個服務)
resources.resourceId(RESOURCE_ID)
// 實現令牌服務, ResourceServerTokenServices實例
.tokenServices(tokenService());
}
/**
* 配置資源服務器如何驗證token有效性
* 1. DefaultTokenServices
* 如果認證服務器和資源服務器同一服務時,則直接采用此默認服務驗證即可
* 2. RemoteTokenServices (當前采用這個)
* 當認證服務器和資源服務器不是同一服務時, 要使用此服務去遠程認證服務器驗證
* */
@Bean
public ResourceServerTokenServices tokenService() {
// 資源服務器去遠程認證服務器驗證 token 是否有效
RemoteTokenServices service = new RemoteTokenServices();
// 請求認證服務器驗證URL,注意:默認這個端點是拒絕訪問的,要設置認證后可訪問
service.setCheckTokenEndpointUrl("http://localhost:8090/auth/oauth/check_token");
// 在認證服務器配置的客戶端id
service.setClientId("wj-pc");
// 在認證服務器配置的客戶端密碼
service.setClientSecret("wj-secret");
return service;
}
}
修改認證服務器的CustomUserDetailsService類:添加指定權限
測試
先用密碼認證模式獲取access_token
然后請求http://localhost:8080/product/list,
這里請求頭需要加上Authorization
,值是Bearer 加上空格再加上認證服務器獲取到的access_token
點擊發送,我們就可以獲取到指定資源了。
控制令牌權限和授權規則
- 資源服務器通過ResourceServerConfigurerAdapter#configure(HttpSecurity http)指定授權規則。
- 禁用Session,因為是基於 token 認證,所以不需要 HttpSession 了指定資源的授權規則,與 SpringSecurity 中的指定方式一樣
- 用#oauth2表達式控制令牌范圍 scope,如果令牌的沒有對應scope權限,則對應資源不允許訪問
ResourceServerConfig中重寫父類方法:
@Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
//不創建session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//資源授權規則
.authorizeRequests().antMatchers("/product/**").hasAuthority("product")
//所有的請求對應訪問的用戶都要有all范圍的權限
.antMatchers("/**").access("#oauth2.hasScope('all')");
}
測試
我們先將scope改掉
再次訪問,就會提示scope的錯誤