《權限系列shiro+cas》---封裝公共驗證模塊

前言

  • 小編最近正在優化權限框架,應對的需求是:在一個分佈式系統中,要有單點登錄功能,還得有集中的權限認證。於是技術選型就找到了shiro和Cas,shiro是Apache旗下的開源授權框架,而Cas是Yale 大學發起的一個企業級的、開源的項目,旨在爲 Web 應用系統提供一種可靠的單點登錄解決方法(屬於 Web SSO)。做授權的框架還有Spring Security,置於Spring Security和Shiro的區別,大家自己去查查吧,下面小編進入正題。

源碼地址

點擊這裏,去小編的GitHub上下載源碼

shiro和cas的關係

  • 用cas實現認證(登錄),用shiro實現授權。

項目之間的依賴關係

  • shiro-cas-authority是公共驗證模塊,它是一個jar工程,主要讓各個應用程序來引用,應用程序一(applicationOne)和應用程序二(applicationTwo)引用shiro-cas-authority,當各個應用程序訪問訪問需要權限的資源時,程序就會跳到shiro-cas-authority來進行權限驗證,其實就是利用shiro來授權。

配置shiro的核心過濾器和cas單點登出過濾器

  • 在公共驗證模塊:shiro-cas-authority是沒有web.xml的,我們將這個模塊打包成jar包供各個應用程序使用,所以web.xml是在各個應用程序中的。
<!-- shiro的核心過濾器----------begin -->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- shiro的核心過濾器----------end -->
<!-- 配置單點登出   begin-->
<listener>
    <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<filter>
    <filter-name>singleSignOutFilter</filter-name>
    <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>singleSignOutFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- 單點登出----------------end -->

shiro與spring整合

配置spring-shiro-authority.xml

<!-- Shiro Filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" />
    <!-- 設定用戶的登錄鏈接,這裏爲cas登錄頁面的鏈接地址可配置回調地址 -->
    <property name="loginUrl" value="${shiro.loginUrl}" />
    <property name="filters">
        <map>
            <!-- 添加casFilter到shiroFilter -->
            <entry key="casFilter" value-ref="casFilter" />
            <entry key="logoutFilter" value-ref="logoutFilter" />
        </map>
    </property>
    <property name="filterChainDefinitions">
        <value>
            /shiro-cas = casFilter
            /logout = logoutFilter
            /**=user
        </value>
    </property>
</bean>

<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
    <!-- 配置驗證成功是的URL -->
    <property name="successUrl" value="${shiro.successUrl}" />
    <!-- 配置驗證錯誤時的失敗URL -->
    <property name="failureUrl" value="${shiro.failureUrl}" />
</bean>

<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
    <!-- 配置驗證錯誤時的失敗頁面 -->
    <property name="redirectUrl" value="${shiro.logoutUrl}" />
</bean>

<bean id="casRealm" class="com.spring.mybatis.realm.UserRealm">
    <!-- 認證通過後的默認角色 -->
    <!-- <property name="defaultRoles" value="ROLE_USER" /> -->
    <!-- cas服務端地址前綴 -->
    <property name="casServerUrlPrefix" value="${shiro.cas.serverUrlPrefix}" />
    <!-- 應用服務地址,用來接收cas服務端票據 -->
    <property name="casService" value="${shiro.cas.service}" />
</bean>

<!-- Shiro's main business-tier object for web-enabled applications -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <!-- <property name="sessionManager" ref="sessionManager" /> -->
    <property name="subjectFactory" ref="casSubjectFactory"></property>
    <property name="realm" ref="casRealm" />
</bean>

<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"></bean>

<bean
    class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager" />
</bean>

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>

<bean
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod"
        value="org.apache.shiro.SecurityUtils.setSecurityManager"></property>
    <property name="arguments" ref="securityManager"></property>
</bean>

spring核心配置文件spring-context-authority.xml

<context:component-scan base-package="com.spring.mybatis"/>

<!--  自動注入properties屬性文件 -->
  <bean id="configProperties111" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
   <property name="locations">
     <list>
       <value>classpath:conf/jdbc.properties</value>
     <!--   <value>classpath:conf/shiro.properties</value> -->
     </list>
   </property>
  </bean>
  <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
      <property name="properties" ref="configProperties111" />
  </bean>  

  <!-- mybatis配置 -->
  <import resource="spring-mybatis-authority.xml"/>
  <!-- shiro配置 -->
  <import resource="spring-shiro-authority.xml"/>

核心Realm的實現

public class UserRealm extends CasRealm {
    @Resource
    private RoleService roleService;
    @Resource
    private UserService userService;

    protected final Map<String, SimpleAuthorizationInfo> roles = new ConcurrentHashMap<String, SimpleAuthorizationInfo>();

    /**
     * 設置角色和權限信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        String account = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = null;
        if (authorizationInfo == null) {
            authorizationInfo = new SimpleAuthorizationInfo();
            List<String> permissions = roleService.getPermissions(account);
            authorizationInfo.addStringPermissions(permissions);
            authorizationInfo.addRoles(roleService.getRoles(account));
            roles.put(account, authorizationInfo);
        }

        return authorizationInfo;
    }


    /**
     * 1、CAS認證 ,驗證用戶身份
     * 2、將用戶基本信息設置到會話中
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {

        AuthenticationInfo authc = super.doGetAuthenticationInfo(token);

        String account = (String) authc.getPrincipals().getPrimaryPrincipal();

        User user = userService.getUserByAccount(account);
     SecurityUtils.getSubject().getSession().setAttribute("user", user);

        return authc;
    }
}
  • 這個核心UserRealm是shiro控制權限的核心,在這個類中,我們將某個用戶的擁有的資源查詢出來,放到SimpleAuthorizationInfo的對象中,當我們訪問後臺方法時,shiro會自動根據SimpleAuthorizationInfo對象的中擁有的資源信息進行比對,檢查用戶是否有權限訪問該資源。

小結

  • 小編並沒有將代碼完全貼出來,要是每條線都貼出來就太麻煩了,大家可以去下載源碼(源碼地址已經給出),讀者可以在調試項目的時候可以加深理解。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章