1. 程式人生 > >Shiro多專案許可權集中管理平臺

Shiro多專案許可權集中管理平臺

專案起源:

公司隨著業務的增長,各業務進行水平擴充套件面臨拆分;隨著業務的拆分各種管理系統撲面而來,為了方便許可權統一管理,不得不自己開發或使用分散式許可權管理(Spring Security)。Spring Security依賴Spring和初級開發人員學習難度大,中小型公司不推薦使用;Apache Shiro是一個強大易用的安全框架,Shiro的API方便理解。經過網上各路大神對shiro與spring security的比較,最終決定使用shiro開發一個獨立的許可權管理平臺。

該專案是在張開濤跟我學shiro Demo基礎上進行開發、功能完善和管理頁面優化,已上傳GitHub歡迎fork、start及提出改進意見。

公用模組:shiro-distributed-platform-core

自定義註解-CurrentUser

通過註解獲取當前登入使用者

請求攔截器-SysUserFilter

攔截所有請求
1.通過shiro Subject 獲取當前使用者的使用者名稱
2.通過使用者名稱獲取使用者資訊
3.將使用者資訊儲存ServletRequest物件中
程式碼示例:

/**
 * 
* @ClassName: SysUserFilter 
* @Description: 請求攔截器
* @author yangzhao
* @date 2017年12月20日 下午2:10:23
*
 */
public class SysUserFilter extends PathMatchingFilter { @Autowired private UserService userService; @Override protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { String username = (String)SecurityUtils.getSubject().getPrincipal(); User user = userService.findByUsername(username); request.setAttribute(Constant.CURRENT_USER,user); return
true; } }

Spring方法攔截器引數繫結-CurrentUserMethodArgumentResolver

通過SpringAOP攔截容器內所有Java方法引數是否有CurrentUser註解,若果有註解標識從NativeWebRequest中獲取user資訊進行引數繫結
程式碼示例:

/**
 * 
* @ClassName: CurrentUserMethodArgumentResolver 
* @Description: Spring方法攔截器引數繫結
* @author yangzhao
* @date 2017年12月20日 下午2:07:55
*
 */
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {

    public CurrentUserMethodArgumentResolver() {
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.hasParameterAnnotation(CurrentUser.class)) {
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        CurrentUser currentUserAnnotation = parameter.getParameterAnnotation(CurrentUser.class);
        return webRequest.getAttribute(currentUserAnnotation.value(), NativeWebRequest.SCOPE_REQUEST);
    }
}

認證攔截器-ServerFormAuthenticationFilter

shiro許可權認證通過後進行頁面跳轉
程式碼示例:

/**
 * 
* @ClassName: ServerFormAuthenticationFilter 
* @Description: 認證攔截器-頁面跳轉
* @author yangzhao
* @date 2017年12月20日 下午2:10:18
*
 */
public class ServerFormAuthenticationFilter extends FormAuthenticationFilter {

    @Override
    protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
        String fallbackUrl = (String) getSubject(request, response)
                .getSession().getAttribute("authc.fallbackUrl");
        if(StringUtils.isEmpty(fallbackUrl)) {
            fallbackUrl = getSuccessUrl();
        }
        WebUtils.redirectToSavedRequest(request, response, fallbackUrl);
    }

公用介面:shiro-distributed-platform-api

許可權系統核心API

AppService-應用API
AreaService-區域API
OrganizationService-組織結構API
ResourceService-資源API
RoleService-角色API
UserService-使用者API

客戶端:shiro-distributed-platform-client

客戶端認證攔截-ClientAuthenticationFilter

1.判斷是否認證通過 若未認證進入下一步
2.從ServletRequest獲取回撥url
3.獲取預設回撥url(客戶端IP和埠)
4.將預設回撥url儲存到session中
5.將第2步中的回撥url儲存到ClientSavedRequest中(方便server回撥時返回到當前請求url)
5.當前請求重定向到server端登入頁面
程式碼示例:

/**
 *
 * @ClassName: AppService
 * @Description: 客戶端認證攔截
 * @author yangzhao
 * @date 2017年12月20日 下午2:03:43
 *
 */
public class ClientAuthenticationFilter extends AuthenticationFilter {

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        Subject subject = getSubject(request, response);
        return subject.isAuthenticated();
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        String backUrl = request.getParameter("backUrl");
        saveRequest(request, backUrl, getDefaultBackUrl(WebUtils.toHttp(request)));
        redirectToLogin(request, response);
        return false;
    }
    protected void saveRequest(ServletRequest request, String backUrl, String fallbackUrl) {
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        HttpServletRequest httpRequest = WebUtils.toHttp(request);
        session.setAttribute("authc.fallbackUrl", fallbackUrl);
        SavedRequest savedRequest = new ClientSavedRequest(httpRequest, backUrl);
        session.setAttribute(WebUtils.SAVED_REQUEST_KEY, savedRequest);
    }
    private String getDefaultBackUrl(HttpServletRequest request) {
        String scheme = request.getScheme();
        String domain = request.getServerName();
        int port = request.getServerPort();
        String contextPath = request.getContextPath();
        StringBuilder backUrl = new StringBuilder(scheme);
        backUrl.append("://");
        backUrl.append(domain);
        if("http".equalsIgnoreCase(scheme) && port != 80) {
            backUrl.append(":").append(String.valueOf(port));
        } else if("https".equalsIgnoreCase(scheme) && port != 443) {
            backUrl.append(":").append(String.valueOf(port));
        }
        backUrl.append(contextPath);
        backUrl.append(getSuccessUrl());
        return backUrl.toString();
    }

}

ClientRealm

ClientRealm繼承自Shiro AuthorizingRealm
該類忽略doGetAuthenticationInfo方法實現,所有認證操作會轉到Server端實現
程式碼示例:

/**
 *
 * @ClassName: ClientRealm
 * @Description: 客戶端shiro Realm
 * @author yangzhao
 * @date 2017年12月20日 下午2:03:43
 *
 */
public class ClientRealm extends AuthorizingRealm {
    private RemoteService remoteService;
    private String appKey;
    public void setRemoteService(RemoteService remoteService) {
        this.remoteService = remoteService;
    }
    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        PermissionContext context = remoteService.getPermissions(appKey, username);
        authorizationInfo.setRoles(context.getRoles());
        authorizationInfo.setStringPermissions(context.getPermissions());
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //永遠不會被呼叫
        throw new UnsupportedOperationException("永遠不會被呼叫");
    }
}

客戶端Session管理-ClientSessionDAO

客戶端與服務端Session同步

客戶端shiro攔截器工廠管理類-ClientShiroFilterFactoryBean

新增兩個方法setFiltersStr、setFilterChainDefinitionsStr,方便在properties檔案中配置攔截器和定義過濾鏈
程式碼示例:

/**
 *
 * @ClassName: ClientShiroFilterFactoryBean
 * @Description: 新增兩個方法setFiltersStr、setFilterChainDefinitionsStr,方便在properties檔案中配置攔截器和定義過濾鏈
 * @author yangzhao
 * @date 2017年12月20日 下午2:03:43
 *
 */
public class ClientShiroFilterFactoryBean extends ShiroFilterFactoryBean implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public void setFiltersStr(String filters) {
        if(StringUtils.isEmpty(filters)) {
            return;
        }
        String[] filterArray = filters.split(";");
        for(String filter : filterArray) {
            String[] o = filter.split("=");
            getFilters().put(o[0], (Filter)applicationContext.getBean(o[1]));
        }
    }

    public void setFilterChainDefinitionsStr(String filterChainDefinitions) {
        if(StringUtils.isEmpty(filterChainDefinitions)) {
            return;
        }
        String[] chainDefinitionsArray = filterChainDefinitions.split(";");
        for(String filter : chainDefinitionsArray) {
            String[] o = filter.split("=");
            getFilterChainDefinitionMap().put(o[0], o[1]);
        }
    }
}

服務端:shiro-distributed-platform-server

介面暴露

通過Spring HttpInvokerServiceExporter工具將shiro-distributed-platform-api模組部分API暴露(remoteService、userService、resourceService),請參考spring-mvc-export-service.xml配置檔案

配置ShiroFilterFactoryBean filterChainDefinitions屬性將以上三個介面許可權設定為遊客、匿名(anon),請參考spring-config-shiro.xml配置檔案

以上屬於原創文章,轉載請註明作者@怪咖
QQ:208275451
Email:[email protected]

相關推薦

Shiro專案許可權集中管理平臺

專案起源: 公司隨著業務的增長,各業務進行水平擴充套件面臨拆分;隨著業務的拆分各種管理系統撲面而來,為了方便許可權統一管理,不得不自己開發或使用分散式許可權管理(Spring Security)。Spring Security依賴Spring和初級開發人員學習

Linux企業生產環境使用者許可權集中管理專案方案案例

企業生產環境使用者許可權集中管理專案方案案例: 1 問題現狀 當前我們公司裡伺服器上百臺,各個伺服器上的管理人員很多(開發+運維+架構+DBA+產品+市場),在大家登入使用Linux伺服器時,不同職能的員工水平不同,因此導致操作很不規範

ansible:集中管理平臺

mysql comm 服務 表示 regex defaults sel let ask 無服務、無agent、采用ssh管理遠程主機、多線程1、配置文件/etc/ansible/ansible.cfg2、管理方式(1)ad-hoc 臨時命令(2)playbook劇本 遠程管

svn對專案許可權進行管理

                昨日一篇有關svn的文章,對Repository理解有偏差,今天重新整理髮表。一 建立Repositories每一個Repositorty是一個倉庫,這個倉庫裡可以放入多個專案。可以對每個專案分別管理,也可以對整個倉庫管理。二 建立Users 三 建立Group 四 分配許可權

使用svn對專案許可權進行管理

一 建立Repositories 每一個Repositorty是一個倉庫,這個倉庫裡可以放入多個專案。可以對每個專案分別管理,也可以對整個倉庫管理。 二 建立Users   三 建立Group   四 分配許可權(對於倉庫) 我們可以對整個Repo

手把手教你用SonarQube+Jenkins搭建--前端專案--程式碼質量管理平臺 (Window系統)

前言 網上教程大多介紹的是Linux系統下SonarQube+Jenkins如何使用,這是因為這兩款軟體一般都是部署在伺服器上,而大多數伺服器,採用的都是Linux系統。大多數伺服器用Linux的原因是: Linux伺服器上的許多軟體都是免費的,Window伺服器的軟體大多是付費的 基於Linux伺服器的解

專案集中許可權管理系統 採用cas +shiro+spring mvc+mbatis+bootstrap單點登入

流程架構圖: 這裡許可權系統也可以理解為cas client專案 系統效果圖: 業務場景:多專案統一認證登入,許可權統一管理,許可權系統管理使用者資料,其他業務系統只維護業務資料,使用者資料一律來自許可權系統 該功能目前經過半個多月的努力 在巨大壓力下終於完成了! 目前國內

Shiro 第二十三章 專案集中許可權管理及分散式會話

在做一些企業內部專案時或一些網際網路後臺時;可能會涉及到集中許可權管理,統一進行多專案的許可權管理;另外也需要統一的會話管理,即實現單點身份認證和授權控制。學習本章之前,請務必先學習《第十章 會話管理》和《第十六章 綜合例項》,本章程式碼都是基於這兩章的程式碼基礎上完成的。本

spring+shiro+jasig-cas+cxf 單點登入點登出簡單統一許可權管理平臺

本文簡單實現在spring框架下對apache shiro與jasig-cas 整合 實現單點登入多點登出統一許可權管理平臺,功能簡單,主要大致講講入門配置。 一、環境:   1、後臺框架:spring3.2+struts2+hibernate4+apache-shiro1

Docker集中化web界面管理平臺-Shipyard部署記錄

安裝docker 順序 ice osi 大致 打開 epo aliyun ges 之前介紹了DOcker的web管理工具DockerUI,下面介紹下Docker的另一個web界面管理工具Shipyard的使用。Shipyard(github)是建立在docker集群管理工具

4、python自動化運維——集中管理平臺Saltstack

python Saltstack linux 自動化運維; 集中化管理平臺——Saltstack Saltstck作為服務器基礎架構集中化管理平臺,具備配置管理,遠程執行,監控等功能。可以簡單地理解為簡化版的puppet,加強版的func。廢話不多說,直接上手。 Saltstack安裝以及配置

5、python自動化運維——集中管理平臺Ansible

python Linux Ansible 自動化運維 集中化管理平臺Ansible 簡介:Ansible是一種集成IT系統的配置管理、應用部署、執行特定任務的開源平臺特點:1、部署簡單,只需在主控端部署Ansible環境,被控端不用進行任何操作2、默認使用SSH協議對設備進行管理3、主從集中化

stf-設備管理平臺搭建

rap png 完成 pen tar 環境 public 需要 body 項目地址: https://github.com/openstf/stf 安裝、使用命令 # 安裝stfbrew install rethinkdb graphicsmagick zeromq pr

快速搭建ELK集中化日誌管理平臺

command uri tun sock one cau else inf span 由於我們的項目是分布式,服務分布於多個服務器上,每次查看日誌都要登錄不同服務器查看,而且查看起來還比較麻煩,老大讓搭一個集中化日誌管理的東西,然後就在網上找到了這個東西ELK E

集中管理平臺saltstack--原理及安裝

斷開連接 master ons 需要 安裝salt groups 客戶端 grep -v 主機 SaltStack原理: Saltstack由master和minion構成,master是服務器端,表示一臺服務器;minion是客戶端,表示有多臺服務器。在master上發

集中管理平臺Ansible詳解(一)

test cfengine key 構建 ron 接口 gid linux平臺 文檔 什麽是ansible? ansible是一種集成IT系統的配置管理、應用部署、執行特定任務的開源平臺.它是基於python語言,由Paramiko和PyYAML兩個關鍵模塊構建。集合了眾多

maven管理平臺專案結構分析

後臺管理平臺專案結構: 1 JAX-WS Web Service(不用,是maven自動生成的) 2 java Resources(最常用,也是maven自動生成的,不是手動建立的) 3 JavaScript Resources(不用,是maven自動生成的,不是手動建立的) 4 Deployed

小型專案SSM+Maven實戰講解:APP資訊管理平臺-developer版

APP管理平臺是一個小型專案,是一個CMS系統,最主要的就是對於SSM(Spring、SpringMVC、Mybatis)框架的整合和Maven的理解,以及GIT託管平臺的使用,另外和有一個BootStrap的使用,在這裡做寫這個心得主要是因為自身對於SSM框架的不熟練,以此來檢驗自己的大腦和開拓自

大資料專案實戰之 --- 某App管理平臺的手機app日誌分析系統(三)

一、建立hive分割槽表 ---------------------------------------------------- 1.建立資料庫 $hive> create database applogsdb; 2.建立分割槽表 編寫指令碼。

docker集中管理平臺--shipyard部署

均衡 特點 -- 方案 ont ack 集群管理 mage 管理工具 Shipyard是建立在docker集群管理工具Citadel之上的可以管理容器、主機等資源的web圖形化工具,包括core和extension兩個版本,core即shipyard主要是把多個 host上