怎么处理整合了shiro的应用的RPC接口鉴权问题

2024-06-22 07:28

本文主要是介绍怎么处理整合了shiro的应用的RPC接口鉴权问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这篇文章分享一下:当一个服务提供者整合了shiro安全框架来实现权限访问控制时,服务消费者通过feign请求服务提供者的接口时的鉴权不通过问题。

问题描述

博主有一个项目pms(权限管理系统),使用了shiro框架来实现鉴权功能,使用的是shiro内置的perms过滤器。

 而服务消费者端,通过feign访问RPC接口,很显然,由于是不同的项目,鉴权肯定是失败的。

package cn.edu.sgu.www.cms.feign.impl;import cn.edu.sgu.www.cms.dto.PermissionInitDTO;
import cn.edu.sgu.www.cms.entity.Permission;
import cn.edu.sgu.www.cms.entity.User;
import cn.edu.sgu.www.cms.feign.FeignService;
import cn.edu.sgu.www.cms.restful.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;import java.util.List;
import java.util.Set;/*** 权限平台feign接口* @author heyunlin* @version 1.0*/
@FeignClient(name = "pms")
public interface PmsFeignService extends FeignService {/*** 根据用户名查询用户信息* @param username 用户名* @param service 应用名* @return JsonResult<User>*/@RequestMapping(value = "/user/selectByUsername", method = RequestMethod.GET)JsonResult<User> selectByUsername(@RequestParam("username") String username,@RequestParam("service") String service);/*** 权限数据初始化* @param permissionInitDTO 权限信息* @return JsonResult<Void>*/@RequestMapping(value = "/permission/resources", method = RequestMethod.POST)JsonResult<Void> resources(PermissionInitDTO permissionInitDTO);/*** 查询应用的非匿名子权限* @param service 应用名* @return JsonResult<List<Permission>>*/@RequestMapping(value = "/permission/selectPermissions", method = RequestMethod.GET)JsonResult<List<Permission>> selectPermissions(@RequestParam("service") String service);/*** 查询应用的匿名子权限* @param service 应用名* @return JsonResult<List<String>>*/@RequestMapping(value = "/permission/selectAnonymityPermissions", method = RequestMethod.GET)JsonResult<List<String>> selectAnonymityPermissions(@RequestParam("service") String service);/*** 通过用户名查询用户权限* @param username 用户名* @param service 应用名* @return JsonResult<Set<String>>*/@RequestMapping(value = "/permission/selectUserPermissions", method = RequestMethod.GET)JsonResult<Set<String>> selectUserPermissions(@RequestParam("username") String username,@RequestParam("service") String service);
}

而在服务消费者启动过程中,需要向pms查询当前应用的权限,所以导致feign请求报错,项目无法启动问题。

package cn.edu.sgu.www.cms.config;import cn.edu.sgu.www.cms.entity.Permission;
import cn.edu.sgu.www.cms.feign.impl.PmsFeignService;
import cn.edu.sgu.www.cms.restful.JsonResult;
import cn.edu.sgu.www.cms.shiro.UserRealm;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** Shiro配置类* @author heyunlin* @version 1.0*/
@Configuration
public class ShiroConfig {@Value("${spring.application.name}")private String service;/*** 登录页面地址*/private String loginPage = "/login.html";/*** 未授权的URL*/private String unauthorizedUrl = "/user/unauthorized";private final PmsFeignService feignService;@Autowiredpublic ShiroConfig(PmsFeignService feignService) {this.feignService = feignService;}/*** 配置安全管理器* @param userRealm UserRealm* @return DefaultWebSecurityManager*/@Beanpublic DefaultWebSecurityManager securityManager(UserRealm userRealm, CacheManager cacheManager) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 设置缓存管理器securityManager.setCacheManager(cacheManager);// 把UserRealm注册到安全管理器securityManager.setRealm(userRealm);return securityManager;}/*** 配置Shiro过滤器工厂* @param securityManager 安全管理器* @return ShiroFilterFactoryBean*/@Beanpublic ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// 注册安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);/** 设置登录页面的地址* 当用户访问认证资源的时候,如果用户没有登录,就会跳转到指定的页面*/shiroFilterFactoryBean.setLoginUrl(loginPage);/** 设置访问未授权资源时重定向的地址* 当用户访问需要授权才能访问资源的时候,如果用户没有该权限,就会跳转到指定的地址*/shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);// 定义资源访问规则Map<String, String> filterMap = new LinkedHashMap<>();/** 定义需要认证才能访问的资源*/filterMap.put("/", "authc");filterMap.put("/index.html", "authc");filterMap.put("/html/*.html", "authc");// knife4jfilterMap.put("/doc.html", "authc");filterMap.put("/v2/api-docs", "authc");filterMap.put("/swagger-resources", "authc");/** 定义不需要认证就能访问的资源*/filterMap.put(loginPage, "anon");filterMap.put("/user/login", "anon");filterMap.put(unauthorizedUrl, "anon");// 查询当前服务的所有匿名子权限JsonResult<List<String>> jsonResult = feignService.selectAnonymityPermissions(service);if (jsonResult.isSuccess()) {List<String> data = jsonResult.getData();for (String url : data) {filterMap.put(url, "anon");}}/** 定义需要指定权限才能访问的资源*/// 查询当前服务的所有非匿名子权限JsonResult<List<Permission>> result = feignService.selectPermissions(service);if (result.isSuccess()) {List<Permission> list = result.getData();for (Permission permission : list) {filterMap.put(permission.getUrl(), "perms[" + permission.getValue() + "]");}}shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);return shiroFilterFactoryBean;}}

之前就遇到了这个问题,但是一直没有管,因为当时还没有想到什么解决的办法。

今天写项目,又遇上了,真气人~

解决方案

博主想到的是通过设置一个请求头,通过过滤器鉴权时先判断请求头是否正确,正确的话直接返回true,不再进行后续的操作。

于是在feign的官网看一下有没有能设置请求头的方法,果然,找到一个请求拦截器可以达到这个效果~

添加请求头

定义一个RequestInterceptor,给请求设置一个请求头perms。

package cn.edu.sgu.www.cms.feign;import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;/*** @author heyunlin* @version 1.0*/
@Component
public class RequestHeaderInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {template.header("perms", "12345");}}

自定义过滤器

在服务生产者项目pms中定义一个过滤器PermsFilter,名字见名知义,就是shiro的perms过滤器。

重写shiro的perms过滤器(PermissionsAuthorizationFilter)的鉴权方法,先判断请求头是否为指定的值,如果是就跳过鉴权,直接返回true。

这样就避免了其他应用访问本应用的接口导致的鉴权失败问题了~

package cn.edu.sgu.www.pms.filter;import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;/*** 定义PermsFilter过滤器(覆盖shiro的perms过滤器)* @author heyunlin* @version 1.0*/
@Slf4j
public class PermsFilter extends PermissionsAuthorizationFilter {@Overridepublic boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {String perms = ((HttpServletRequest) request).getHeader("perms");if (perms != null && perms.equals("12345")) {log.debug("发现请求头perms,当前请求为搜权应用发起的请求,跳过鉴权~");return true;}return super.isAccessAllowed(request, response, mappedValue);}}

注册过滤器到shiro

将刚刚创建的过滤器注册到shiro,博主直接把原来的perms过滤器覆盖掉了。

// 自定义过滤器
Map<String, Filter> filterMap = new HashMap<>();filterMap.put("perms", new PermsFilter());shiroFilterFactoryBean.setFilters(filterMap);

好了,文章就分享到这里了,希望看完之后对你有所帮助~

这篇关于怎么处理整合了shiro的应用的RPC接口鉴权问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1083659

相关文章

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

MyBatis-plus处理存储json数据过程

《MyBatis-plus处理存储json数据过程》文章介绍MyBatis-Plus3.4.21处理对象与集合的差异:对象可用内置Handler配合autoResultMap,集合需自定义处理器继承F... 目录1、如果是对象2、如果需要转换的是List集合总结对象和集合分两种情况处理,目前我用的MP的版本

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired