找回密码
 立即注册
首页 业界区 业界 SpringBoot-shiro-jwt-dubbo-redis分布式统一权限系统( ...

SpringBoot-shiro-jwt-dubbo-redis分布式统一权限系统(完结)

瞿佳悦 2026-1-14 16:25:02
分布式统一权限系统
设计


shiro-mgt:用户、角色、资源的定义,资源对应网关的定义,动态链的定义
shiro鉴权服务集群:会话信息、Realm信息
dubbo-app集群:实际业务相关
模块依赖


Springboot-shiro-gateway-handler功能:

  • dubbo业务服务转换http通讯
  • 认证与鉴权服务化消费者
  • 生成业务服务化消费者
springboot-shiro-producer功能:

  • 认证与鉴权的服务化生成者
springboot-shiro-mgt功能:

  • 认证与鉴权的服务化消费者
springboot-shiro-dubbo-app-handler功能:

  • 生成业务服务化生产者
动态过滤器链

实现动态过滤器链,我们需要保证以下几个特性:
1、持久化:原有的properties内容放入数据库,
2、有序性:因过滤器链有序加载的特性,读取过滤器链的时保证其有序性
3、服务化:过滤器链的服务做成dubbo服务,做到集中式管理
4、同步性:不同业务系统对于过滤器链的加载需要同步
5、热加载:过滤器链修改之后,各个业务系统不需要重启服务,以达到热加载的目的
实现持久化、有序化

过滤器链包含的字段:
  1. package com.itheima.shiro.vo;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import org.apache.commons.lang3.builder.ToStringBuilder;import org.apache.commons.lang3.builder.ToStringStyle;import java.io.Serializable;@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class FilterChainVo implements Serializable {    /**     * 主键     */    private String id;    /**     * 描述     */    private String urlName;    /**     * 路径     */    private String url;    /**     * 拦截器名称     */    private String filterName;    /**     * 所需角色,可省略,用逗号分隔     */    private String roles;    /**     * 所需权限,可省略,用逗号分隔     */    private String permissions;    /**     * 排序     */    private Integer sortNo;    private String enableFlag;    private static final long serialVersionUID = 1L;    @Override    public String toString() {        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);    }}
复制代码
实现服务化

目的:使所有的服务器链查询请求都通过这个服务来调用。
  1. package com.itheima.shiro.face;import com.itheima.shiro.vo.FilterChainVo;import java.util.List;/** * @Description:过滤器链服务化接口 */public interface FilterChainFace {    /**     * @Description 查询所有有效的过滤器链     */    List findFilterChainList();}
复制代码
  1. package com.itheima.shiro.faceImpl;import com.itheima.shiro.face.FilterChainFace;import com.itheima.shiro.pojo.FilterChain;import com.itheima.shiro.service.FilterChainService;import com.itheima.shiro.utils.BeanConv;import com.itheima.shiro.utils.EmptyUtil;import com.itheima.shiro.vo.FilterChainVo;import org.apache.dubbo.config.annotation.Service;import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/** * @Description:过滤器链服务化接口 */@Service(version = "1.0.0",retries = 3,timeout = 5000)public class FilterChainFaceImpl implements FilterChainFace {    @Autowired    FilterChainService filterChainService;    @Override    public List findFilterChainList() {        List filterChainList = filterChainService.findFilterChainList();        if (!EmptyUtil.isNullOrEmpty(filterChainList)){            // 将数据库返回的数据结构转换成标准的过滤器链格式            return BeanConv.toBeanList(filterChainList, FilterChainVo.class);        }        return null;    }}
复制代码
实现同步性

先读取数据库的过滤器链,调用上面filterChainFace服务

  • FilterChainBridgeService:过滤器链桥接器service接口层
  • FilterChainBridgeServiceImpl:过滤器链桥接器service接口层实现
将过滤器链加载到shiro中

  • ShiroFilerChainService:shiro过滤器链服务加载接口
  • ShiroFilerChainService:shiro过滤器链服务加载接口实现
  1. package com.itheima.shiro.core.bridge;import com.itheima.shiro.vo.FilterChainVo;import javax.servlet.FilterChain;import java.util.List;/** * @Description:自定义过滤器桥接接口 */public interface FilterChainBridgeService {    /**     * @Description 查询所有有效的过滤器链     */    List findFilterChainList();}
复制代码
  1. package com.itheima.shiro.client;import com.itheima.shiro.core.bridge.FilterChainBridgeService;import com.itheima.shiro.face.FilterChainFace;import com.itheima.shiro.vo.FilterChainVo;import org.apache.dubbo.config.annotation.Reference;import org.springframework.stereotype.Service;import java.util.List;/** * @Description:自定义过滤器桥接接口实现 */@Service("filterChainBridgeService")public class FilterChainBridgeServiceImpl implements FilterChainBridgeService {    @Reference(version = "1.0.0")    private FilterChainFace filterChainFace;    @Override    public List findFilterChainList() {        return filterChainFace.findFilterChainList();    }}
复制代码
  1. package com.itheima.shiro.service;import com.itheima.shiro.vo.FilterChainVo;import java.util.List;/** * @Description:过滤器同步接口 */public interface ShiroFilerChainService {    /**     * @Description 启动时,启动定时器,每隔2分钟动态加载数据库里面的过滤器链     */    void init();    /**     * @Description 使用DefaultFilterChainManager的addToChain方法构建过滤器链     */    void initFilterChains(List filterChainVos);}
复制代码
  1. package com.itheima.shiro.service.impl;import com.itheima.shiro.core.bridge.FilterChainBridgeService;import com.itheima.shiro.core.impl.CustomDefaultFilterChainManager;import com.itheima.shiro.service.ShiroFilerChainService;import com.itheima.shiro.vo.FilterChainVo;import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;import org.apache.shiro.web.filter.mgt.NamedFilterList;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/** * @Description:过滤器同步接口实现 */@Service("shiroFilerChainService")public class ShiroFilerChainServiceImpl implements ShiroFilerChainService {    //注入过滤器链管理者    @Autowired    private CustomDefaultFilterChainManager defaultFilterChainManager;    //使用桥接器读取数据库内的过滤器链    @Autowired    FilterChainBridgeService filterChainBridgeService;    private Map defaultFilterChains;    //定时器    private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);    // 每个服务器启动都会加载这个方法    @Override    @PostConstruct    public void init() {        defaultFilterChains = new LinkedHashMap();        // 延时为0,每120秒执行一次        executorService.scheduleAtFixedRate(new Runnable() {            @Override            public void run() {                initFilterChains(filterChainBridgeService.findFilterChainList()) ;            }        }, 0, 120, TimeUnit.SECONDS);    }    @Override    public void initFilterChains(List filterChainVos) {        //1、首先删除以前老的filter,构建默认的过滤器链        defaultFilterChainManager.getFilterChains().clear();        //2、加载过滤器链        for (FilterChainVo urlFilterVo : filterChainVos) {            String url = urlFilterVo.getUrl();            String filterName = urlFilterVo.getFilterName();            String[] filterNames = filterName.split(",");            for (String name : filterNames) {                //注册所有filter,包含自定义的过滤器                switch(name){                    case "anon":                        defaultFilterChainManager.addToChain(url, name);                        break;                    case "authc":                        defaultFilterChainManager.addToChain(url, name);                        break;                    case "roles":                        defaultFilterChainManager.addToChain(url, name, urlFilterVo.getRoles());                        break;                    case "perms":                        defaultFilterChainManager.addToChain(url, name,urlFilterVo.getPermissions());                        break;                    case "role-or":                        defaultFilterChainManager.addToChain(url, name,urlFilterVo.getRoles());                        break;                    case "kicked-out":                        defaultFilterChainManager.addToChain(url, name);                        break;                    case "jwt-authc":                        defaultFilterChainManager.addToChain(url, name);                        break;                    case "jwt-roles":                        defaultFilterChainManager.addToChain(url, name, urlFilterVo.getRoles());                        break;                    case "jwt-perms":                        defaultFilterChainManager.addToChain(url, name,urlFilterVo.getPermissions());                        break;                    default:                        break;                }            }        }    }}
复制代码
实现热加载

为了实现热加载我们需要定义以下3个类:

  • CustomDefaultFilterChainManager:自定义的默认过滤器链管理者
  • CustomPathMatchingFilterChainResolver:自定义的路径匹配过滤器链解析器
  • CustomShiroFilterFactoryBean:自定义shiro过滤器工厂bean
CustomDefaultFilterChainManager:主要是把原来对象的创建交于spring容器,同时指定过滤器,然后构建过滤器链
  1. package com.itheima.shiro.core.impl;import org.apache.shiro.util.StringUtils;import org.apache.shiro.web.filter.AccessControlFilter;import org.apache.shiro.web.filter.authc.AuthenticationFilter;import org.apache.shiro.web.filter.authz.AuthorizationFilter;import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;import org.apache.shiro.web.filter.mgt.NamedFilterList;import javax.annotation.PostConstruct;import javax.servlet.Filter;import java.util.LinkedHashMap;import java.util.Map;/** * @Description:自定义过滤器链管理者 */public class CustomDefaultFilterChainManager extends DefaultFilterChainManager {    //登录地址    private String loginUrl;    //登录成功之后跳转地址    private String successUrl;    //未授权跳转地址    private String unauthorizedUrl;    /**     * @Description 构建过滤器和过滤器链的map对象,加载默认的过滤器链     */    public CustomDefaultFilterChainManager() {        setFilters(new LinkedHashMap());        setFilterChains(new LinkedHashMap());        addDefaultFilters(true);    }    @PostConstruct    public void init(){        Map defaultFilters = getFilters();        //apply global settings if necessary:        for (Filter filter : defaultFilters.values()) {            applyGlobalPropertiesIfNecessary(filter);        }    }    private void applyGlobalPropertiesIfNecessary(Filter filter) {        applyLoginUrlIfNecessary(filter);        applySuccessUrlIfNecessary(filter);        applyUnauthorizedUrlIfNecessary(filter);    }    private void applyLoginUrlIfNecessary(Filter filter) {        String loginUrl = getLoginUrl();        if (StringUtils.hasText(loginUrl) && (filter instanceof AccessControlFilter)) {            AccessControlFilter acFilter = (AccessControlFilter) filter;            //only apply the login url if they haven't explicitly configured one already:            String existingLoginUrl = acFilter.getLoginUrl();            if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) {                acFilter.setLoginUrl(loginUrl);            }        }    }    private void applySuccessUrlIfNecessary(Filter filter) {        String successUrl = getSuccessUrl();        if (StringUtils.hasText(successUrl) && (filter instanceof AuthenticationFilter)) {            AuthenticationFilter authcFilter = (AuthenticationFilter) filter;            //only apply the successUrl if they haven't explicitly configured one already:            String existingSuccessUrl = authcFilter.getSuccessUrl();            if (AuthenticationFilter.DEFAULT_SUCCESS_URL.equals(existingSuccessUrl)) {                authcFilter.setSuccessUrl(successUrl);            }        }    }    private void applyUnauthorizedUrlIfNecessary(Filter filter) {        String unauthorizedUrl = getUnauthorizedUrl();        if (StringUtils.hasText(unauthorizedUrl) && (filter instanceof AuthorizationFilter)) {            AuthorizationFilter authzFilter = (AuthorizationFilter) filter;            //only apply the unauthorizedUrl if they haven't explicitly configured one already:            String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();            if (existingUnauthorizedUrl == null) {                authzFilter.setUnauthorizedUrl(unauthorizedUrl);            }        }    }    /**     * @Description 加载自定义过滤器的对象     * @param customFilters 自定义过滤器的map架构     * @return     */    public void setCustomFilters(Map customFilters){        for (Map.Entry entry : customFilters.entrySet()) {            addFilter(entry.getKey(), entry.getValue(), false);        }    }    /**     * @Description 不再使用shiro容器去构建,而是交于spring去构建     */    @Override    protected void initFilter(Filter filter) {    }    public String getLoginUrl() {        return loginUrl;    }    public void setLoginUrl(String loginUrl) {        this.loginUrl = loginUrl;    }    public String getSuccessUrl() {        return successUrl;    }    public void setSuccessUrl(String successUrl) {        this.successUrl = successUrl;    }    public String getUnauthorizedUrl() {        return unauthorizedUrl;    }    public void setUnauthorizedUrl(String unauthorizedUrl) {        this.unauthorizedUrl = unauthorizedUrl;    }}
复制代码
CustomPathMatchingFilterChainResolver这里主要核心内容是:指定使用过滤器链管理器为自己定的过滤器管理器
  1. package com.itheima.shiro.core.impl;import lombok.extern.log4j.Log4j2;import org.apache.shiro.web.filter.mgt.FilterChainManager;import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;import javax.servlet.FilterChain;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;/** * @Description:自定义路径解析器 */@Log4j2public class CustomPathMatchingFilterChainResolver extends PathMatchingFilterChainResolver {    private CustomDefaultFilterChainManager defaultFilterChainManager;    public CustomDefaultFilterChainManager getDefaultFilterChainManager() {        return defaultFilterChainManager;    }    public void setDefaultFilterChainManager(CustomDefaultFilterChainManager defaultFilterChainManager) {        this.defaultFilterChainManager = defaultFilterChainManager;    }    public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {        //不在使用默认的过滤器链管理者,而是使用自定义的过滤器管理者        FilterChainManager filterChainManager = getDefaultFilterChainManager();        if (!filterChainManager.hasChains()) {            return null;        }        String requestURI = getPathWithinApplication(request);        //the 'chain names' in this implementation are actually path patterns defined by the user.  We just use them        //as the chain name for the FilterChainManager's requirements        for (String pathPattern : filterChainManager.getChainNames()) {            // If the path does match, then pass on to the subclass implementation for specific checks:            if (pathMatches(pathPattern, requestURI)) {                if (log.isTraceEnabled()) {                    log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "].  " +                            "Utilizing corresponding filter chain...");                }                return filterChainManager.proxy(originalChain, pathPattern);            }        }        return null;    }}
复制代码
  1. package com.itheima.shiro.core.impl;import lombok.extern.log4j.Log4j2;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.filter.mgt.FilterChainManager;import org.apache.shiro.web.filter.mgt.FilterChainResolver;import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;import org.apache.shiro.web.mgt.WebSecurityManager;import org.apache.shiro.web.servlet.AbstractShiroFilter;import org.springframework.beans.factory.BeanInitializationException;/** * @Description:重写shirod过滤器工厂 */@Log4j2public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean {    PathMatchingFilterChainResolver chainResolver ;    public void setChainResolver(PathMatchingFilterChainResolver chainResolver) {        this.chainResolver = chainResolver;    }    protected AbstractShiroFilter createInstance() throws Exception {        log.debug("Creating Shiro Filter instance.");        SecurityManager securityManager = getSecurityManager();        if (securityManager == null) {            String msg = "SecurityManager property must be set.";            throw new BeanInitializationException(msg);        }        if (!(securityManager instanceof WebSecurityManager)) {            String msg = "The security manager does not implement the WebSecurityManager interface.";            throw new BeanInitializationException(msg);        }        FilterChainManager manager = createFilterChainManager();        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);    }    private static final class SpringShiroFilter extends AbstractShiroFilter {        protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {            super();            if (webSecurityManager == null) {                throw new IllegalArgumentException("WebSecurityManager property cannot be null.");            }            setSecurityManager(webSecurityManager);            if (resolver != null) {                setFilterChainResolver(resolver);            }        }    }}
复制代码
shiroConfig修改
  1. package com.itheima.shiro.config;import com.itheima.shiro.constant.SuperConstant;import com.itheima.shiro.core.ShiroDbRealm;import com.itheima.shiro.core.filter.*;import com.itheima.shiro.core.impl.*;import com.itheima.shiro.properties.PropertiesUtil;import lombok.extern.log4j.Log4j2;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.session.mgt.eis.SessionDAO;import org.apache.shiro.spring.LifecycleBeanPostProcessor;import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.apache.shiro.web.servlet.SimpleCookie;import org.redisson.Redisson;import org.redisson.api.RedissonClient;import org.redisson.config.Config;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import javax.servlet.Filter;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;/** * @Description 权限配置类 */@Configuration@ComponentScan(basePackages = {"com.itheima.shiro.core"})@EnableConfigurationProperties({ShiroRedisProperties.class})@Log4j2public class ShiroConfig {    @Autowired    private ShiroRedisProperties shiroRedisProperties;    @Autowired    JwtTokenManager jwtTokenManager;    /**     * @Description redission客户端     */    @Bean("redissonClientForShiro")    public RedissonClient redissonClient() {        log.info("=====初始化redissonClientForShiro开始======");        String[] nodeList = shiroRedisProperties.getNodes().split(",");        Config config = new Config();        if (nodeList.length == 1) {            config.useSingleServer().setAddress(nodeList[0])                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())                    .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())                    .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());        } else {            config.useClusterServers().addNodeAddress(nodeList)                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())                    .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())                    .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());        }        RedissonClient redissonClient =  Redisson.create(config);        log.info("=====初始化redissonClientForShiro完成======");        return redissonClient;    }    /**     * @Description 创建cookie对象     */    @Bean(name="sessionIdCookie")    public SimpleCookie simpleCookie(){        SimpleCookie simpleCookie = new SimpleCookie();        simpleCookie.setName("ShiroSession");        return simpleCookie;    }    /**     * @Description 权限管理器     * @param     * @return     */    @Bean(name="securityManager")    public DefaultWebSecurityManager defaultWebSecurityManager(){        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();        securityManager.setRealm(shiroDbRealm());        securityManager.setSessionManager(shiroSessionManager());        return securityManager;    }    /**     * @Description 密码比较器     */    @Bean    public HashedCredentialsMatcher hashedCredentialsMatcher (){        RetryLimitCredentialsMatcher matcher = new RetryLimitCredentialsMatcher(SuperConstant.HASH_ALGORITHM,redissonClient());        matcher.setHashIterations(SuperConstant.HASH_INTERATIONS);        return matcher;    }    /**     * @Description 自定义RealmImpl     */    @Bean(name="shiroDbRealm")    public ShiroDbRealm shiroDbRealm(){        ShiroDbRealm shiroDbRealm =new ShiroDbRealmImpl();        shiroDbRealm.setCredentialsMatcher(hashedCredentialsMatcher());        return shiroDbRealm;    }    /**     * @Description 自定义session会话存储的实现类 ,使用Redis来存储共享session,达到分布式部署目的     */    @Bean("redisSessionDao")    public SessionDAO redisSessionDao(){        RedisSessionDao sessionDAO =   new RedisSessionDao();        sessionDAO.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout());        return sessionDAO;    }    /**     * @Description 会话管理器     */    @Bean(name="sessionManager")    public ShiroSessionManager shiroSessionManager(){        ShiroSessionManager sessionManager = new ShiroSessionManager();        sessionManager.setSessionDAO(redisSessionDao());        sessionManager.setSessionValidationSchedulerEnabled(false);        sessionManager.setSessionIdCookieEnabled(true);        sessionManager.setSessionIdCookie(simpleCookie());        sessionManager.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout());        return sessionManager;    }    /**     * @Description 保证实现了Shiro内部lifecycle函数的bean执行     */    @Bean(name = "lifecycleBeanPostProcessor")    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {        return new LifecycleBeanPostProcessor();    }    /**     * @Description AOP式方法级权限检查     */    @Bean    @DependsOn("lifecycleBeanPostProcessor")    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);        return defaultAdvisorAutoProxyCreator;    }    /**     * @Description 配合DefaultAdvisorAutoProxyCreator事项注解权限校验     */    @Bean    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();        aasa.setSecurityManager(defaultWebSecurityManager());        return new AuthorizationAttributeSourceAdvisor();    }    /**     * @Description 自定义过滤器定义     */    private Map filters() {        Map map = new HashMap();        map.put("role-or", new RolesOrAuthorizationFilter());        map.put("kicked-out", new KickedOutAuthorizationFilter(redissonClient(), redisSessionDao(), shiroSessionManager()));        map.put("jwt-authc", new JwtAuthcFilter(jwtTokenManager));        map.put("jwt-perms", new JwtPermsFilter());        map.put("jwt-roles", new JwtRolesFilter());        return map;    }        // ===========================以下是修改部分================================    @Bean    public CustomDefaultFilterChainManager defaultFilterChainManager(){        CustomDefaultFilterChainManager defaultFilterChainManager = new CustomDefaultFilterChainManager();        defaultFilterChainManager.setCustomFilters(filters());        defaultFilterChainManager.setLoginUrl("/login");        defaultFilterChainManager.setSuccessUrl("/home");        defaultFilterChainManager.setUnauthorizedUrl("/login");        return defaultFilterChainManager;    }    @Bean    public CustomPathMatchingFilterChainResolver chainResolver(){        CustomPathMatchingFilterChainResolver chainResolver = new CustomPathMatchingFilterChainResolver();        //指定过滤器管理者        chainResolver.setDefaultFilterChainManager(defaultFilterChainManager());        return chainResolver;    }    /**     * @Description Shiro过滤器     */    @Bean("shiroFilter")    public ShiroFilterFactoryBean shiroFilterFactoryBean(){        CustomShiroFilterFactoryBean shiroFilter = new CustomShiroFilterFactoryBean();        shiroFilter.setChainResolver(chainResolver());        shiroFilter.setSecurityManager(defaultWebSecurityManager());        return shiroFilter;    }}
复制代码
shiro-client客户端

shiro-client作为jar的依赖,满足以下需求:
1、非侵入式:使用者只需要对jar依赖和做少量的配置,就可以达到统一鉴权的目标
2、可扩展性:用户除使用提供的过滤器外,可以轻松安自己的业务区定义过滤器
3、集中式管理:依赖jar之后,shiro-mgt后台可以同时管控多个平台的权限的认证、鉴权、及动态配置过滤器链
依赖关系


原理分析

springboot-shiro-framework-client项目向上继承了springboot-shiro-framework-core项目,springboot-shiro-framework-core是主要实现认证、鉴权、过滤器定义、会话统一、realm缓存的核心项目。
springboot-shiro-framework-client项目以jar的方式被需要做权限控制的gateway项目所依赖,再由gateway通过对springboot-shiro-producer的dubbo消费,以达到统一认证、鉴权
springboot-shiro-framework-client模块实现了springboot-shiro-framework-core接口的3个类:
UserBridgeServiceImpl:提供用户基本资源操作的业务实现
FilterChainBridgeServiceImpl:提供过滤器链接口的查询
ResourceBridgeServiceImpl:提供资源查询
  1. package com.itheima.shiro.client;import com.itheima.shiro.core.bridge.FilterChainBridgeService;import com.itheima.shiro.face.FilterChainFace;import com.itheima.shiro.vo.FilterChainVo;import org.apache.dubbo.config.annotation.Reference;import org.springframework.stereotype.Service;import java.util.List;/** * @Description:自定义过滤器桥接接口实现 */@Service("filterChainBridgeService")public class FilterChainBridgeServiceImpl implements FilterChainBridgeService {    @Reference(version = "1.0.0")    private FilterChainFace filterChainFace;    @Override    public List findFilterChainList() {        return filterChainFace.findFilterChainList();    }}
复制代码
  1. package com.itheima.shiro.client;import com.itheima.shiro.core.bridge.ResourceBridgeService;import com.itheima.shiro.face.ResourceAdapterFace;import com.itheima.shiro.vo.ResourceVo;import org.apache.dubbo.config.annotation.Reference;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;import java.util.List;/** * @Description:网关资源桥接器接口实现 */@Component("resourceBridgeService")public class ResourceBridgeServiceImpl implements ResourceBridgeService {    @Value("${itheima.resource.systemcode}")    private String systemCode;    @Reference(version = "1.0.0")    ResourceAdapterFace resourceAdapterFace;    @Override    public List findValidResourceVoAll(String systemCode) {        return resourceAdapterFace.findValidResourceVoAll(systemCode);    }}
复制代码
  1. package com.itheima.shiro.client;import com.itheima.shiro.constant.CacheConstant;import com.itheima.shiro.core.SimpleCacheService;import com.itheima.shiro.core.base.ShiroUser;import com.itheima.shiro.core.base.SimpleMapCache;import com.itheima.shiro.core.base.SimpleToken;import com.itheima.shiro.core.bridge.UserBridgeService;import com.itheima.shiro.face.UserAdapterFace;import com.itheima.shiro.utils.BeanConv;import com.itheima.shiro.utils.EmptyUtil;import com.itheima.shiro.utils.ShiroUserUtil;import com.itheima.shiro.vo.ResourceVo;import com.itheima.shiro.vo.RoleVo;import com.itheima.shiro.vo.UserVo;import lombok.extern.slf4j.Slf4j;import org.apache.dubbo.config.annotation.Reference;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.util.ByteSource;import org.redisson.api.RBucket;import org.redisson.api.RedissonClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.TimeUnit;/** * @Description 权限桥接器 */@Slf4j@Component("userBridgeService")public class UserBridgeServiceImpl implements UserBridgeService {    @Reference(version = "1.0.0")    private UserAdapterFace userAdapterFace;    @Autowired    private SimpleCacheService simpleCacheService;    @javax.annotation.Resource(name = "redissonClientForShiro")    private RedissonClient redissonClient;    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken,String realmName) {        SimpleToken token = (SimpleToken)authcToken;        UserVo user  = this.findUserByLoginName(token.getUsername());        if(EmptyUtil.isNullOrEmpty(user)){            throw new UnknownAccountException("账号不存在");        }        ShiroUser shiroUser = BeanConv.toBean(user, ShiroUser.class);        String sessionId = ShiroUserUtil.getShiroSessionId();        String cacheKeyResourcesIds = CacheConstant.RESOURCES_KEY_IDS+sessionId;        shiroUser.setResourceIds(this.findResourcesIdsList(cacheKeyResourcesIds,user.getId()));        String salt = user.getSalt();        String password = user.getPassWord();        return new SimpleAuthenticationInfo(shiroUser, password, ByteSource.Util.bytes(salt), realmName);    }    @Override    public SimpleAuthorizationInfo getAuthorizationInfo(ShiroUser shiroUser) {        UserVo user = BeanConv.toBean(shiroUser, UserVo.class);        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        String sessionId = ShiroUserUtil.getShiroSessionId();        //查询用户拥有的角色        String cacheKeyRole = CacheConstant.ROLE_KEY + sessionId;        info.addRoles(this.findRoleList(cacheKeyRole, user.getId()));        //查询用户拥有的资源        String cacheKeyResources = CacheConstant.RESOURCES_KEY + sessionId;        info.addStringPermissions(this.findResourcesList(cacheKeyResources, user.getId()));        return info;    }    @Override    public List findRoleList(String cacheKeyRole, String userId) {        List roles = new ArrayList();        if (simpleCacheService.getCache(cacheKeyRole) != null) {            roles = (List) simpleCacheService.getCache(cacheKeyRole).get(cacheKeyRole);        } else {            roles = userAdapterFace.findRoleByUserId(userId);            if (roles.size() > 0) {                //用户角色存放到map                Map mapRole = new HashMap();                mapRole.put(cacheKeyRole, roles);                //新建SimpleMapCache实例并放入缓存管理器                SimpleMapCache cacheRole = new SimpleMapCache(cacheKeyRole, mapRole);                simpleCacheService.creatCache(cacheKeyRole, cacheRole);            }        }        List rolesLabel = new ArrayList();        for (RoleVo role : roles) {            rolesLabel.add(role.getLabel());        }        return rolesLabel;    }    @Override    public List findResourcesList(String cacheKeyResources,String userId) {        List resourcesList = new ArrayList();        if (simpleCacheService.getCache(cacheKeyResources) != null) {            resourcesList = (List) simpleCacheService.getCache(cacheKeyResources).get(cacheKeyResources);        } else {            resourcesList = userAdapterFace.findResourceByUserId(userId);            if (resourcesList.size() > 0) {                //用户资源存放到map                Map mapResource = new HashMap();                mapResource.put(cacheKeyResources, resourcesList);                //新建SimpleMapCache实例并放入缓存管理器                SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);                simpleCacheService.creatCache(cacheKeyResources, cacheResource);            }        }        List resourcesLabel = new ArrayList();        for (ResourceVo resources : resourcesList) {            resourcesLabel.add(resources.getLabel());        }        return resourcesLabel;    }    @Override    public UserVo findUserByLoginName(String loginName) {        String key = CacheConstant.FIND_USER_BY_LOGINNAME+loginName;        RBucket rBucket = redissonClient.getBucket(key);        UserVo user = rBucket.get();        if (!EmptyUtil.isNullOrEmpty(user)) {            return user;        }else {            user = userAdapterFace.findUserByLoginName(loginName);            if (!EmptyUtil.isNullOrEmpty(user)) {                rBucket.set(user, 300, TimeUnit.SECONDS);                return user;            }        }        rBucket.set(new UserVo(), 3, TimeUnit.SECONDS);        return null;    }    @Override    public List findResourcesIdsList(String cacheKeyResources,String userId) {        List resourcesList = new ArrayList();        if (simpleCacheService.getCache(cacheKeyResources) != null) {            resourcesList = (List) simpleCacheService.getCache(cacheKeyResources).get(cacheKeyResources);        } else {            resourcesList = userAdapterFace.findResourceByUserId(userId);            if (resourcesList.size() > 0) {                //用户资源存放到map                Map mapResource = new HashMap();                mapResource.put(cacheKeyResources, resourcesList);                //新建SimpleMapCache实例并放入缓存管理器                SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);                simpleCacheService.creatCache(cacheKeyResources, cacheResource);            }        }        List resourcesLabel = new ArrayList();        for (ResourceVo resources : resourcesList) {            resourcesLabel.add(resources.getId());        }        return resourcesLabel;    }    @Override    public void loadUserAuthorityToCache(ShiroUser user) {        String sessionId = user.getSessionId();        List roles = userAdapterFace.findRoleByUserId(user.getId());        //创建角色cachaeKey        String cacheKeyRole = CacheConstant.ROLE_KEY + sessionId;        //用户角色存放到map        Map mapRole = new HashMap();        mapRole.put(cacheKeyRole, roles);        //新建SimpleMapCache实例并放入缓存管理器        SimpleMapCache cacheRole = new SimpleMapCache(cacheKeyRole, mapRole);        simpleCacheService.creatCache(cacheKeyRole, cacheRole);        List resourcesList = userAdapterFace.findResourceByUserId(user.getId());        if (resourcesList.size() > 0) {            //创建资源cachaeKey            String cacheKeyResources = CacheConstant.RESOURCES_KEY + sessionId;            //用户资源存放到map            Map mapResource = new HashMap();            mapResource.put(cacheKeyResources, resourcesList);            //新建SimpleMapCache实例并放入缓存管理器            SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);            simpleCacheService.creatCache(cacheKeyResources, cacheResource);        }    }}
复制代码
shiro-gateway网关

原理分析


​        1、依赖springboot-shiro-framework-client实现认证、鉴权、过滤器定义、会话统一、realm缓存等功能
​        2、springboot-shiro-mgt管理后台持久化网关资源
​        3、springboot-shiro-handler实现网关资源查询服务化
​        4、gateway-service依据持久化的网关资源,动态创建消费端服务
代码实现

网关资源持久化

这里在原有资源的基础上,增加的网关资源的管理:
​                1、定义网关systemcode,用以区分不同网关系统
​                2、定义访问的路径
​                3、定义资源的唯一标识,作为权限控制的标识
​                4、定义业务端dubbo服务端接口、目标方法、传入阐述、轮训算法、超时时间、重试次数等参数,这些内容会在gateway-service项目中解析
网关资源服务化
  1. ResourceAdapterFace:网关资源服务接口ResourceAdapterFaceImpl:网关资源服务接口实现ResourceBridgeService:网关资源桥接器接口ResourceBridgeServiceImpl:网关资源桥接器接口实现
复制代码
  1. package com.itheima.shiro.face;import com.itheima.shiro.vo.ResourceVo;import java.util.List;/** * @Description:网关资源服务接口 */public interface ResourceAdapterFace {    /**     * @Description 获得当前系统是由有效的dubbo的资源     */    List findValidResourceVoAll(String systemCode);}
复制代码
  1. package com.itheima.shiro.faceImpl;import com.itheima.shiro.face.ResourceAdapterFace;import com.itheima.shiro.pojo.Resource;import com.itheima.shiro.service.ResourceService;import com.itheima.shiro.utils.BeanConv;import com.itheima.shiro.utils.EmptyUtil;import com.itheima.shiro.vo.ResourceVo;import org.apache.dubbo.config.annotation.Service;import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/** * @Description:网关资源服务接口实现 */@Service(version = "1.0.0", retries = 3,timeout = 5000)public class ResourceAdapterFaceImpl implements ResourceAdapterFace {    // 网关资源的持久化服务    @Autowired    ResourceService resourceService;    @Override    public List findValidResourceVoAll(String systemCode) {        List resourceList =  resourceService.findValidResourceVoAll(systemCode);        if (!EmptyUtil.isNullOrEmpty(resourceList)){            return BeanConv.toBeanList(resourceList, ResourceVo.class);        }        return  null;    }}
复制代码
  1. package com.itheima.shiro.core.bridge;import com.itheima.shiro.vo.ResourceVo;import java.util.List;/** * @Description:网关资源桥接器接口 */public interface ResourceBridgeService {    /**     * @Description 查询当前系统所有有效的DUBBO类型的服务     * @param systemCode 系统编号:与mgt添加系统编号相同     * @return     */    public List findValidResourceVoAll(String systemCode);}
复制代码
  1. package com.itheima.shiro.client;import com.itheima.shiro.core.bridge.ResourceBridgeService;import com.itheima.shiro.face.ResourceAdapterFace;import com.itheima.shiro.vo.ResourceVo;import org.apache.dubbo.config.annotation.Reference;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;import java.util.List;/** * @Description:网关资源桥接器接口实现 */@Component("resourceBridgeService")public class ResourceBridgeServiceImpl implements ResourceBridgeService {    @Value("${itheima.resource.systemcode}")    private String systemCode;    @Reference(version = "1.0.0")    ResourceAdapterFace resourceAdapterFace;    @Override    public List findValidResourceVoAll(String systemCode) {        return resourceAdapterFace.findValidResourceVoAll(systemCode);    }}
复制代码
动态消费端


CacheWare:缓存仓库
CacheWareService:缓存仓库服务接口
CacheWareServiceImpl:缓存仓库服务接口实现
CacheWareSyncService:缓存仓库同步服务接口
CacheWareSyncServiceImpl:缓存仓库同步服务接口实现
LoginAction:登录相应接口
GateWayController:相应层的统一入口
  1. package com.itheima.shiro.pojo;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.lang.reflect.Method;import java.lang.reflect.Type;/** * @Description 缓存仓库可执行类 */@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic class CacheWare {    //执行类    private String serviceName;    //执行方法    private String methodName;    //方法对象    private Method method;    //参数类型    private Class methodParamsClass;    //代理类    private Object proxy;}
复制代码
CacheWareService

其主要负责:
1、缓存的清除
2、向map容器中创建缓存
3、获得缓存仓库执行对象
  1. package com.itheima.shiro.cache;import com.google.common.collect.Multimap;import com.itheima.shiro.pojo.CacheWare;/** * @Description:缓存仓库服务 */public interface CacheWareService {    /**     * @Description 清除缓存     */    void clearCacheWare();    /**     * @Description 向map容器中创建缓存     * @param cacheWareMap     */    void createCacheWare(Multimap cacheWareMap);    /**     * @Description 获得缓存仓库执行对象     * @param serviceName 服务名     * @param methodName  方法名     * @return {@link CacheWare}     *     */    CacheWare queryCacheWare(String serviceName, String methodName);}
复制代码
  1. package com.itheima.shiro.cache.impl;import com.google.common.collect.ArrayListMultimap;import com.google.common.collect.Multimap;import com.itheima.shiro.cache.CacheWareService;import com.itheima.shiro.pojo.CacheWare;import com.itheima.shiro.utils.EmptyUtil;import org.springframework.stereotype.Service;import java.util.Collection;/** * @Description:缓存仓库服务实现 */@Service("cacheWareService")public class CacheWareServiceImpl implements CacheWareService {    private Multimap cacheWareMap = ArrayListMultimap.create();    @Override    public void clearCacheWare() {        cacheWareMap.clear();    }    @Override    public void createCacheWare(Multimap cacheWareMap) {        this.cacheWareMap = cacheWareMap;    }    @Override    public CacheWare queryCacheWare(String serviceName, String methodName) {        if (EmptyUtil.isNullOrEmpty(serviceName)||EmptyUtil.isNullOrEmpty(methodName)){            return null;        }        String key = serviceName+":"+methodName;        Collection cacheWares =cacheWareMap.get(key);        return EmptyUtil.isNullOrEmpty(cacheWares)?null:cacheWares.iterator().next();    }}
复制代码
CacheWareSyncService

其主要职责:
1、启动时、调用CacheWareService的创建缓存方法初始化缓存仓库
2、同步缓存仓库
3、网关资源转化缓存仓库可执行对象
4、从dubbo中,初始化代理对象
注意:为了在多个网关系统下,接口转换的无干扰,读取的只是本网关所对应的资源
  1. package com.itheima.shiro.cache;import com.itheima.shiro.pojo.CacheWare;import com.itheima.shiro.vo.ResourceVo;/** * @Description:缓存仓库同步接口 */public interface CacheWareSyncService {    /**     * @Description 初始化缓存仓库     */    void initCacheWare();    /**     * @Description 同步缓存仓库     */    void refreshCacheWare();    /**     * @Description 资源转换缓存仓库可执行对象     */    CacheWare resourceConvCacheWare(ResourceVo resource);    /**     * @Description 初始化代理对象     * @param interfaceClass 接口     * @param loadbalance 算法     * @param version 版本     * @param timeout 超时时间     * @param retries 重试次数     */    Object initProxy(Class interfaceClass,                     String loadbalance,                     String version,                     Integer timeout,                     Integer retries);    /**     * @Description 回收资源     */    void destoryCacheWare();}
复制代码
  1. package com.itheima.shiro.cache.impl;import com.google.common.collect.ArrayListMultimap;import com.google.common.collect.Multimap;import com.itheima.shiro.cache.CacheWareService;import com.itheima.shiro.cache.CacheWareSyncService;import com.itheima.shiro.core.bridge.ResourceBridgeService;import com.itheima.shiro.pojo.CacheWare;import com.itheima.shiro.utils.EmptyUtil;import com.itheima.shiro.vo.ResourceVo;import lombok.extern.log4j.Log4j2;import org.apache.dubbo.config.ApplicationConfig;import org.apache.dubbo.config.ReferenceConfig;import org.apache.dubbo.config.RegistryConfig;import org.apache.dubbo.config.utils.ReferenceConfigCache;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;import javax.annotation.Resource;import java.lang.reflect.Method;import java.util.List;import java.util.Set;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/** * @Description:缓存仓库同步服务接口实现 */@Service("cacheWareSyncService")@Log4j2public class CacheWareSyncServiceImpl implements CacheWareSyncService {    @Value("${itheima.resource.systemcode}")    private String systemCode;    @Autowired    CacheWareService cacheWareService;    @Autowired    ResourceBridgeService resourceBridgeService;    @Autowired    private ApplicationConfig applicationConfig;    @Autowired    private RegistryConfig registryConfig;    //线程池    private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);    @Override    @PostConstruct    public void initCacheWare() {        executorService.scheduleAtFixedRate(new Runnable() {            @Override            public void run() {                refreshCacheWare();            }        }, 0, 2, TimeUnit.MINUTES);    }    @Override    public void refreshCacheWare() {        //获得网关资源        List resources = resourceBridgeService.findValidResourceVoAll(systemCode);        //判断网关资源是否为空,则清空所有map容器中的可执行对象        if (EmptyUtil.isNullOrEmpty(resources)){            cacheWareService.clearCacheWare();        }        Multimap cacheWareMultimap = ArrayListMultimap.create();        //把网关资源转换为缓存仓库可执行对象        for (ResourceVo resource : resources) {            if (EmptyUtil.isNullOrEmpty(resource.getServiceName())||                EmptyUtil.isNullOrEmpty(resource.getMethodName())){                log.warn("网关资源定义不完整:{}",resource.toString());                continue;            }            CacheWare cacheWare = resourceConvCacheWare(resource);            if (!EmptyUtil.isNullOrEmpty(cacheWare)){                String key = cacheWare.getServiceName()+":"+cacheWare.getMethodName();                cacheWareMultimap.put(key, cacheWare);            }        }        //放入map容器        cacheWareService.createCacheWare(cacheWareMultimap);    }    @Override    public CacheWare resourceConvCacheWare(ResourceVo resource) {        //网关资源服务接口        Class serviceClass = null;        try {            serviceClass = Class.forName(resource.getServiceName());        } catch (ClassNotFoundException e) {            log.error("为在容器中发现{}接口类",resource.getServiceName());            return null;        }        String serviceNameAll = resource.getServiceName();        // 获得类名        String serviceName = serviceNameAll.substring(serviceNameAll.lastIndexOf(".")+1).toLowerCase();        //对应的执行方法        Method[] methods = serviceClass.getDeclaredMethods();        Method methodTarget = null;        for (Method method : methods) {            if (method.getName().equals(resource.getMethodName())){                methodTarget = method;                break;            }        }        //如果方法获取失败        if (EmptyUtil.isNullOrEmpty(methodTarget)){            log.error("为在容器中发现{}方法",resource.getMethodName());            return null;        }        //获得方法上的传入参数        Class[] parameterTypes = methodTarget.getParameterTypes();        Class methodParamsClassTarget = null;        for (Class parameterType : parameterTypes) {            if (parameterType.getName().equals(resource.getMethodParam())){                methodParamsClassTarget = parameterType;                break;            }        }        //构建服务代理类        Object proxy = initProxy(serviceClass, resource.getLoadbalance(), resource.getDubboVersion(), resource.getTimeout(), resource.getRetries());        //构建缓存仓库可执行对象        CacheWare cacheWare = CacheWare.builder()                .serviceName(serviceName)                .methodName(resource.getMethodName())                .method(methodTarget)                .methodParamsClass(methodParamsClassTarget)                .proxy(proxy).build();        return cacheWare;    }    // 获取代理类    @Override    public Object initProxy(Class interfaceClass, String loadbalance, String version, Integer timeout, Integer retries) {        // 构建消费端        ReferenceConfig referenceConfig = new ReferenceConfig();        referenceConfig.setApplication(applicationConfig);        referenceConfig.setRegistry(registryConfig);        referenceConfig.setLoadbalance(EmptyUtil.isNullOrEmpty(loadbalance)?"random":loadbalance);        referenceConfig.setInterface(interfaceClass);        referenceConfig.setVersion(version);        referenceConfig.setTimeout(EmptyUtil.isNullOrEmpty(timeout)?20000:timeout);        referenceConfig.setCheck(false);        // 指定重试次数        referenceConfig.setRetries(EmptyUtil.isNullOrEmpty(retries)?0:retries);        ReferenceConfigCache cache = ReferenceConfigCache.getCache();        return cache.get(referenceConfig);    }    @Override    public void destoryCacheWare() {        executorService.shutdownNow();    }}
复制代码
网关资源解析

其主要负责:
1、传入参数处理
2、获得可执行缓存仓库
3、执行远程服务
4、处理返回结果
  1. package com.itheima.shiro.web;import com.alibaba.fastjson.JSONObject;import com.itheima.shiro.base.BaseRequest;import com.itheima.shiro.cache.CacheWareService;import com.itheima.shiro.constant.GateWayConstant;import com.itheima.shiro.pojo.CacheWare;import com.itheima.shiro.response.MultiResponse;import com.itheima.shiro.response.PageResponse;import com.itheima.shiro.response.SingleResponse;import com.itheima.shiro.utils.EmptyUtil;import com.itheima.shiro.view.JsonResult;import lombok.extern.log4j.Log4j2;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.*;import java.lang.reflect.Method;/** * @Description:网关统一入口 */@Controller@Log4j2public class GateWayController {    @Autowired    CacheWareService cacheWareService;    /**     * @Description 请求入口     * @param serviceName 服务名称     * @param methodName 目标方法     * @param baseRequest 请求对象     * @return     */    @RequestMapping(value = "{serviceName}/{methodName}",method = RequestMethod.POST)    @ResponseBody    public JsonResult postGateWay(@PathVariable("serviceName") String serviceName,                                  @PathVariable("methodName") String methodName,                                  @RequestBody BaseRequest baseRequest) throws Exception{        JsonResult jsonResult = null;        if (EmptyUtil.isNullOrEmpty(serviceName)||EmptyUtil.isNullOrEmpty(methodName)){            jsonResult = jsonResult.builder()                    .result(GateWayConstant.FAIL)                    .msg("参数缺失")                    .code(GateWayConstant.PARAMETERS_MISSING)                    .build();                    return  jsonResult;        }        //传入参数处理        JSONObject jsonObject = null;        Object datas = baseRequest.getDatas();        if (!EmptyUtil.isNullOrEmpty(datas)){            jsonObject = JSONObject.parseObject(jsonObject.toJSONString(datas));        }        //获得缓存仓库可执行对象        CacheWare cacheWare = cacheWareService.queryCacheWare(serviceName, methodName);        //执行远程服务        Object proxy = cacheWare.getProxy();        Method method = cacheWare.getMethod();        Class methodParamsClass = cacheWare.getMethodParamsClass();        Object result = null;        if (EmptyUtil.isNullOrEmpty(methodParamsClass)){            result = method.invoke(proxy);        }else {            Object arg = JSONObject.toJavaObject(jsonObject, methodParamsClass);            result = method.invoke(proxy,arg);        }        //处理放回结果        return  convResult(result);    }    /**     * @Description 处理请求结果     */    private JsonResult convResult(Object result) {        JsonResult jsonResult = JsonResult.builder()                .result(GateWayConstant.SUCCEED)                .msg("相应正常")                .code(GateWayConstant.SUCCEED_CODE)                .build();        if (EmptyUtil.isNullOrEmpty(result)) {            jsonResult = JsonResult.builder()                    .result(GateWayConstant.FAIL)                    .msg("返回结果为空")                    .code(GateWayConstant.RESULT_ISNULLOREMPTY)                    .build();            return jsonResult;        }        if (result instanceof SingleResponse) {            BeanUtils.copyProperties(result, jsonResult);            @SuppressWarnings("rawtypes")            SingleResponse singleResponse = (SingleResponse) result;            jsonResult.setDatas(singleResponse.getValue());        } else if (result instanceof MultiResponse) {            BeanUtils.copyProperties(result, jsonResult);            @SuppressWarnings("rawtypes")            MultiResponse multiResponse = (MultiResponse) result;            jsonResult.setDatas(multiResponse.getValues());        } else if (result instanceof PageResponse) {            BeanUtils.copyProperties(result, jsonResult);            PageResponse pageResponse = (PageResponse)result;            jsonResult.setDatas( pageResponse.getValues());        } else {            jsonResult = JsonResult.builder()                    .result(GateWayConstant.FAIL)                    .msg("返回结果格式不正确")                    .code(GateWayConstant.RESULT_MISSING)                    .build();            return jsonResult;        }        return jsonResult;    }}
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

4 天前

举报

懂技术并乐意极积无私分享的人越来越少。珍惜
您需要登录后才可以回帖 登录 | 立即注册