SpringCloud Alibaba微服务实战三十 | 统一资源服务器配置模块
前面文章咱们对比过网关授权与微服务授权的区别,文章也提到了,如果要实现微服务授权,一般会构建一个独立的资源服务器配置模块,否则每个后端业务都需要进行资源服务器的配置,那本节内容我们就来完成此功能。
由于间隔时间较久,建议先阅读下面两篇相关文章回顾一下。
话不多说,我们直接开始代码改造。
认证服务器改造
首先我们需要改造认证服务器,需要认证服务器在构建用户权限的时候使用的是权限标识字段。对于代码而言只需要 UserDetailServiceImpl#loadUserByUsername()
中修改即可。
@Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { //获取本地用户 SysUser sysUser = sysUserMapper.selectByUserName(userName); if(sysUser != null){ //获取当前用户的所有角色 List<SysRole> roleList = sysRoleService.listRolesByUserId(sysUser.getId()); sysUser.setRoles(roleList.stream().map(SysRole::getRoleCode).collect(Collectors.toList())); List<Integer> roleIds = roleList.stream().map(SysRole::getId).collect(Collectors.toList()); //获取所有角色的权限 List<SysPermission> permissionList = sysPermissionService.listPermissionsByRoles(roleIds); //基于方法拦截.只需放入用户权限标识即可 List<String> permissionMethodList = permissionList.stream() .map(SysPermission::getPermission) .collect(Collectors.toList()); sysUser.setPermissions(permissionMethodList); //构建oauth2的用户 return buildUserDetails(sysUser); }else{ throw new UsernameNotFoundException("用户["+userName+"]不存在"); } }
网关改造
网关服务器不再需要进行用户权限校验,所以我们需要将相关校验逻辑全部删除。
@Configuration public class SecurityConfig { @Bean SecurityWebFilterChain webFluxSecurityFilterChain(ServerHttpSecurity http) throws Exception{ http .httpBasic().disable() .csrf().disable(); return http.build(); } }
独立资源服务器配置模块
完成了上面两步后就到了最重要的步骤了,需要建立一个独立的资源服务器配置模块,用于其他模块引用。
首先我们得建立一个单独的资源服务模块 cloud-component-security-starter
,如下为改造后的代码结构图。
然后,要让一个普通后端服务成为资源服务器,需要有一个配置类继承 ResourceServerConfigurerAdapter
并进行相关配置,那在我们独立的资源服务器模块我们首先得创建一个这样的配置类,这个比较简单,只需从之前的模块中拷贝一份出来。
public class CloudResourceServerConfigure extends ResourceServerConfigurerAdapter { private CustomAccessDeniedHandler accessDeniedHandler; private CustomAuthenticationEntryPoint exceptionEntryPoint; private TokenStore tokenStore; @Value("${security.oauth2.resource.id}") private String resourceId ; @Autowired(required = false) public void setAccessDeniedHandler(CustomAccessDeniedHandler accessDeniedHandler) { this.accessDeniedHandler = accessDeniedHandler; } @Autowired(required = false) public void setExceptionEntryPoint(CustomAuthenticationEntryPoint exceptionEntryPoint) { this.exceptionEntryPoint = exceptionEntryPoint; } @Autowired(required = false) public void setTokenStore(TokenStore tokenStore) { this.tokenStore = tokenStore; } @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll() .antMatchers( "/v2/api-docs/**", "/swagger-resources/**", "/swagger-ui.html", "/webjars/**" ).permitAll() .anyRequest().authenticated() .and() .csrf().disable(); } @Override public void configure(ResourceServerSecurityConfigurer resources) { DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); UserAuthenticationConverter userTokenConverter = new CustomUserAuthenticationConverter(); accessTokenConverter.setUserTokenConverter(userTokenConverter); if (exceptionEntryPoint != null) { resources.authenticationEntryPoint(exceptionEntryPoint); } if (accessDeniedHandler != null) { resources.accessDeniedHandler(accessDeniedHandler); } resources.resourceId(resourceId).tokenStore(tokenStore); } }
现在有了资源服务器配置,那其他模块如何引入这个配置类呢?
这里我们可以借助SpringBoot的Enable模块驱动能力,通过@EnableXXX注解导入配置类。
我们创建一个自定义注解类 EnableCloudResourceServer
,其他模块通过 @EnableCloudResourceServer
注解即可导入资源服务器配置
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @EnableResourceServer //开启资源服务器 @Import({CloudResourceServerConfigure.class, TokenStoreConfigure.class}) public @interface EnableCloudResourceServer { }
最后我们知道微服务授权是基于方法拦截,基于方法拦截我们就需要开启 @EnableGlobalMethodSecurity
,并且需要将我们自定义的权限注解功能迁移过来。所以我们再创建一个配置类用于配置上述功能。
@EnableGlobalMethodSecurity(prePostEnabled = true) public class CloudSecurityAutoConfigure extends GlobalMethodSecurityConfiguration { @Bean @ConditionalOnMissingBean(name = "accessDeniedHandler") public CustomAccessDeniedHandler accessDeniedHandler() { return new CustomAccessDeniedHandler(); } @Bean @ConditionalOnMissingBean(name = "authenticationEntryPoint") public CustomAuthenticationEntryPoint authenticationEntryPoint() { return new CustomAuthenticationEntryPoint(); } @Override protected MethodSecurityExpressionHandler createExpressionHandler() { return new CustomMethodSecurityExpressionHandler(); } }
经过上面的改造,一个独立的资源服务器创建成功了,现在剩下的就是对微服务的改造。
微服务改造
-
在maven中删除原oauth2.0的相关配置,引入自定义
cloud-component-security-starter
<dependency> <groupId>com.jianzh5.cloud</groupId> <artifactId>cloud-component-security-starter</artifactId> </dependency>
-
删除所有资源服务器相关代码(此过程略)
-
修改主启动类,通过
@EnableCloudResourceServer
引入资源服务器配置
@EnableDiscoveryClient @SpringCloudApplication @EnableCloudResourceServer public class AccountServiceApplication { public static void main(String[] args) { SpringApplication.run(AccountServiceApplication.class, args); } }
-
在需要拦截的Controller方法中添加自定义权限拦截注解
@PreAuthorize("hasPrivilege('queryAccount')")
当然也可以使用SpringSecurity原生注解@PreAuthorize("hasAuthority('queryAccount')")
,两者作用一样。
@GetMapping("/account/getByCode/{accountCode}") @PreAuthorize("hasPrivilege('queryAccount')") //@PreAuthorize("hasAuthority('queryAccount')") public ResultData<AccountDTO> getByCode(@PathVariable(value = "accountCode") String accountCode){ AccountDTO accountDTO = accountService.selectByCode(accountCode); return ResultData.success(accountDTO); }
测试
我们访问一个没有权限的方法会出现如下错误提示,表明独立资源服务器成功配置
{ "status": 500, "message": "不允许访问", "data": null, "success": false, "timestamp": 1619052359563 }
提示:@PreAuthorize 注解的异常,抛出AccessDeniedException异常,不会被accessDeniedHandler捕获,而是会被全局异常捕获。如果需要自定义
@PreAuthorize
错误异常,可以通过全局的@RestControllerAdvice
进行异常拦截
拦截后的自定义异常如下:
{ "status": 2003, "message": "没有权限访问该资源", "data": null, "success": false, "timestamp": 1619052359563 }
以上,希望对你有所帮助!
这里为大家准备了一份小小的礼物,关注公众号,输入如下代码,即可获得百度网盘地址,无套路领取!
001:《程序员必读书籍》
002:《从无到有搭建中小型互联网公司后台服务架构与运维架构》
003:《互联网企业高并发解决方案》
004:《互联网架构教学视频》
006:《SpringBoot实现点餐系统》
007:《SpringSecurity实战视频》
008:《Hadoop实战教学视频》
009:《腾讯2019Techo开发者大会PPT》
010: 微信交流群
本文分享自微信公众号 - JAVA日知录(javadaily)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
一个Bug,让我发现了Java界的.AJ(锥)!
持续坚持原创输出,点击蓝字关注我吧 作者:小傅哥博客:https://bugstack.cn ❝ 沉淀、分享、成长,让自己和他人都能有所收获!😜 ❞ 目录 一、前言 二、满脑子都是骚操作 1. 遇到问题 2. 发现问题 3. 排查问题 三、如何正确使用 Aspect 的 .aj 类 1. 安装 AspectJ 2. AspectJ 插件 3. 添加依赖 aspectjrt.jar 4. 配置AspectJ编译器 5. 案例测试 四、总结 五、系列推荐 一、前言 话我放这,踩过的坑越多头发越少! 说来也是奇怪,只要是学编程的,从初次接触的 Java 到安装 JDK、IDEA、MYSQL, 再到接触 Spring、MyBatis、RPC、MQ,哪怕有时候在浅的坑也会跳进去尝尝鲜,一遍抓着头发,一手点着鼠标也几乎是你的常态。你的键盘里总是有很多被抓碎的头发! 但,哪怕是抓了这么头发,还是遇到了一个满脑子都是骚操作的小伙。傅哥,我的切面怎么拦截不到?我是照着你的《SpringBoot 中间件设计和开发》专栏写的,你给我看看吧,我都弄了一天了 接下来我带着大家一起看看什么是快乐星球,他是怎么一...
- 下一篇
what's new in dubbogo v1.5.6
作者 | 铁城 dubbo-go 社区 committer dubbogo 社区近期发布了 dubbogo v1.5.6。该版本和 dubbo 2.7.8 对齐,提供了命令行工具,并提供了多种加载配置的方式。 相关改进实在太多,本文只列出相关重大 feature 和 性能提升项。 1. 命令行工具 熟悉 dubbo 的朋友可能知道 dubbo 支持 telnet 命令行在线调试。 本次发布也增加了 dubbo-go 的 cli 命令行工具,可以方便用户直连特定服务,通过编写 json 文件来定义传输结构和数据,发起调用进行在线调试,打印返回数据和耗时情况。 目前支持嵌套 struct,但是只支持单个参数的请求包和回包。数据类型由于需要在 json 中定义,只支持 golang 基本数据类型:字符串、整形、浮点。 社区后续会再发一篇文章,着重讲解其原理和实现。相关 pr 为 https://github.com/apache/dubbo-go/pull/818 由 dubbogo 最年轻的 00 后 apache committer 李志信同学实现。 2. 代理实现扩展 重构 Proxy...
相关文章
文章评论
共有0条评论来说两句吧...