接着上一篇博客: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的错误