SpringCloud Alibaba二十五 | 网关Restful接口拦截

简介: SpringCloud Alibaba二十五 | 网关Restful接口拦截

前言


之前在 集成RBAC授权 的文章中提到了SpringCloud可以「基于路径匹配器授权」在网关层进行用户权限校验,这种方式的实现原理是Springcloud Gateway接受到请求后根据 ReactiveAuthorizationManager#check(Mono<Authentication> authenticationMono, AuthorizationContext authorizationContext) 方法基于 AntPathMatcher校验当前访问的URL是否在用户拥有的权限URL中,如果能匹配上则说明拥有访问权限并放行到后端服务,否则提示用户无访问权限。

具体实现方式在上面文章中有阐述,如果有不清楚的可以再次查阅。 文章地址:

http://javadaily.cn/articles/2020/08/07/1596772909329.html

不过之前的实现方式有个问题,就是不支持restful风格的url路径。

例如一个微服务有如下API

GET     /v1/pb/user

POST   /v1/pb/user

PUT    /v1/pb/user

这样在网关通过 request.getURI().getPath()方法获取到用户请求路径的时候都是同一个地址,给一个用户授予 /v1/pb/user权限后他就拥有了 GETPUTPOST三种不同权限,很显然这样不能满足精细权限控制。本章内容我们就来解决这个Restful接口拦截的问题,使其能支持精细化的权限控制。


场景演示


我们看下实际的案例,演示下这种场景。在 account-service模块下增加一个博客用户管理功能,有如下的接口方法:

接口URL HTTP方法 接口说明
/blog/user POST 保存用户
/blog/user/{id} GET 查询用户
/blog/user/{id} DELETE 删除用户
/blog/user/{id} PUT 更新用户信息

然后我们在 sys_permission表中添加2个用户权限,再将其授予给用户角色

在网关层的校验方法中可以看到已经增加了2个权限

由于DELETE 和 PUT对应的权限路径都是 /blog/user/{id},这样就是当给用户授予了查询权限后此用户也拥有了删除和更新的权限。


解决方案


看到这里大部分同学应该想到了,要想实现Restful风格的精细化权限管理单单通过URL路径是不行的,需要搭配Method一起使用。

最关键的点就是「需要给权限表加上方法字段,然后在网关校验的时候即判断请求路径又匹配请求方法。」 实现步骤如下:

  • 修改权限表,新增方法字段

  • loadUserByUsername()方法构建用户权限的时候将权限对应的Method也拼接在权限上,关键代码如下:
@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);
  //拼接method
  List<String> permissionUrlList = permissionList.stream()
                    .map(item -> "["+item.getMethod()+"]"+item.getUrl())
                    .collect(Collectors.toList());
  sysUser.setPermissions(permissionUrlList);
  //构建oauth2的用户
  return buildUserDetails(sysUser);
 }else{
  throw  new UsernameNotFoundException("用户["+userName+"]不存在");
 }
}

通过上面的代码构建的用户权限如下:

[GET]/account-service/blog/user/{id}

[POST]/account-service/blog/user

可以通过代码调试查看:

  • 权限校验方法AccessManager#check(),校验[MEHOTD]RequestPath 格式
@Override
public Mono<AuthorizationDecision> check(Mono<Authentication> authenticationMono, AuthorizationContext authorizationContext) {
 ServerWebExchange exchange = authorizationContext.getExchange();
 ServerHttpRequest request = exchange.getRequest();
 //请求资源
 String requestPath = request.getURI().getPath();
 //拼接method
 String methodPath = "["+request.getMethod()+"]" + requestPath;
 // 1. 对应跨域的预检请求直接放行
 if(request.getMethod() == HttpMethod.OPTIONS){
  return Mono.just(new AuthorizationDecision(true));
 }
 // 是否直接放行
 if (permitAll(requestPath)) {
  return Mono.just(new AuthorizationDecision(true));
 }
 return authenticationMono.map(auth -> new AuthorizationDecision(checkAuthorities(auth, methodPath)))
   .defaultIfEmpty(new AuthorizationDecision(false));
}

校验方法 checkAuthorities()

private boolean checkAuthorities(Authentication auth, String requestPath) {
 if(auth instanceof OAuth2Authentication){
  OAuth2Authentication authentication = (OAuth2Authentication) auth;
  String clientId = authentication.getOAuth2Request().getClientId();
  log.info("clientId is {}",clientId);
  //用户的权限集合
  Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
  return authorities.stream()
    .map(GrantedAuthority::getAuthority)
    //ROLE_开头的为角色,需要过滤掉
    .filter(item -> !item.startsWith(CloudConstant.ROLE_PREFIX))
    .anyMatch(permission -> ANT_PATH_MATCHER.match(permission, requestPath));
 }
 return true;
}


  • 这样当请求Delete方法时就会提示没有权限

这里还有另外一种方案,实现的原理跟上面差不多,只简单提一下。

首先还是得在权限表中新增METHOD字段,这是必须的。

然后项目中使用的权限类是 SimpleGrantedAuthority,这个只能存储一个权限字段,我们可以自定义一个权限实体类,让其可以存储url 和 method。

@Data
public class MethodGrantedAuthority implements GrantedAuthority {
    private String method;
    private String url;
    public MethodGrantedAuthority(String method, String url){
        this.method = method;
        this.url = url;
    }
    @Override
    public String getAuthority() {
        return "["+method+"]" + url;
    }
}

UserDetailServiceImpl中构建用户权限时使用自定义的 MethodGrantedAuthority

网关层校验的方法还是需要跟上面一样,既校验Method 又 校验 URL。

以上就解决了在网关层校验Restful风格的用户权限校验,希望对你有所帮助!

目录
相关文章
|
1月前
|
人工智能 安全 Java
AI 时代:从 Spring Cloud Alibaba 到 Spring AI Alibaba
本次分享由阿里云智能集团云原生微服务技术负责人李艳林主讲,主题为“AI时代:从Spring Cloud Alibaba到Spring AI Alibaba”。内容涵盖应用架构演进、AI agent框架发展趋势及Spring AI Alibaba的重磅发布。分享介绍了AI原生架构与传统架构的融合,强调了API优先、事件驱动和AI运维的重要性。同时,详细解析了Spring AI Alibaba的三层抽象设计,包括模型支持、工作流智能体编排及生产可用性构建能力,确保安全合规、高效部署与可观测性。最后,结合实际案例展示了如何利用私域数据优化AI应用,提升业务价值。
139 4
|
1月前
|
人工智能 自然语言处理 Java
Spring Cloud Alibaba AI 入门与实践
本文将介绍 Spring Cloud Alibaba AI 的基本概念、主要特性和功能,并演示如何完成一个在线聊天和在线画图的 AI 应用。
356 7
|
2月前
|
存储 SpringCloudAlibaba Java
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论。
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
|
2月前
|
SpringCloudAlibaba 负载均衡 Dubbo
【SpringCloud Alibaba系列】Dubbo高级特性篇
本章我们介绍Dubbo的常用高级特性,包括序列化、地址缓存、超时与重试机制、多版本、负载均衡。集群容错、服务降级等。
【SpringCloud Alibaba系列】Dubbo高级特性篇
|
2月前
|
SpringCloudAlibaba JavaScript Dubbo
【SpringCloud Alibaba系列】Dubbo dubbo-admin安装教程篇
本文介绍了 Dubbo-Admin 的安装和使用步骤。Dubbo-Admin 是一个前后端分离的项目,前端基于 Vue,后端基于 Spring Boot。安装前需确保开发环境(Windows 10)已安装 JDK、Maven 和 Node.js,并在 Linux CentOS 7 上部署 Zookeeper 作为注册中心。
【SpringCloud Alibaba系列】Dubbo dubbo-admin安装教程篇
|
2月前
|
SpringCloudAlibaba Dubbo Java
【SpringCloud Alibaba系列】Dubbo基础入门篇
Dubbo是一款高性能、轻量级的开源Java RPC框架,提供面向接口代理的高性能RPC调用、智能负载均衡、服务自动注册和发现、运行期流量调度、可视化服务治理和运维等功能。
【SpringCloud Alibaba系列】Dubbo基础入门篇
|
2月前
|
Java Nacos Sentinel
Spring Cloud Alibaba:一站式微服务解决方案
Spring Cloud Alibaba(简称SCA) 是一个基于 Spring Cloud 构建的开源微服务框架,专为解决分布式系统中的服务治理、配置管理、服务发现、消息总线等问题而设计。
458 13
Spring Cloud Alibaba:一站式微服务解决方案
|
4月前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
4月前
|
JSON SpringCloudAlibaba Java
Springcloud Alibaba + jdk17+nacos 项目实践
本文基于 `Springcloud Alibaba + JDK17 + Nacos2.x` 介绍了一个微服务项目的搭建过程,包括项目依赖、配置文件、开发实践中的新特性(如文本块、NPE增强、模式匹配)以及常见的问题和解决方案。通过本文,读者可以了解如何高效地搭建和开发微服务项目,并解决一些常见的开发难题。项目代码已上传至 Gitee,欢迎交流学习。
279 1
Springcloud Alibaba + jdk17+nacos 项目实践
|
4月前
|
XML Java 数据格式
如何使用 Spring Cloud 实现网关
如何使用 Spring Cloud 实现网关
66 3