前言
- 小編最近正在優化權限框架,應對的需求是:在一個分佈式系統中,要有單點登錄功能,還得有集中的權限認證。於是技術選型就找到了shiro和Cas,shiro是Apache旗下的開源授權框架,而Cas是Yale 大學發起的一個企業級的、開源的項目,旨在爲 Web 應用系統提供一種可靠的單點登錄解決方法(屬於 Web SSO)。做授權的框架還有Spring Security,置於Spring Security和Shiro的區別,大家自己去查查吧,下面小編進入正題。
源碼地址
點擊這裏,去小編的GitHub上下載源碼
shiro和cas的關係
項目之間的依賴關係
- shiro-cas-authority是公共驗證模塊,它是一個jar工程,主要讓各個應用程序來引用,應用程序一(applicationOne)和應用程序二(applicationTwo)引用shiro-cas-authority,當各個應用程序訪問訪問需要權限的資源時,程序就會跳到shiro-cas-authority來進行權限驗證,其實就是利用shiro來授權。
配置shiro的核心過濾器和cas單點登出過濾器
- 在公共驗證模塊:shiro-cas-authority是沒有web.xml的,我們將這個模塊打包成jar包供各個應用程序使用,所以web.xml是在各個應用程序中的。
<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>
<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>
shiro與spring整合
配置spring-shiro-authority.xml
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="${shiro.loginUrl}" />
<property name="filters">
<map>
<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">
<property name="successUrl" value="${shiro.successUrl}" />
<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="casServerUrlPrefix" value="${shiro.cas.serverUrlPrefix}" />
<property name="casService" value="${shiro.cas.service}" />
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<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"/>
<bean id="configProperties111" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:conf/jdbc.properties</value>
</list>
</property>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="properties" ref="configProperties111" />
</bean>
<import resource="spring-mybatis-authority.xml"/>
<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對象的中擁有的資源信息進行比對,檢查用戶是否有權限訪問該資源。
小結
- 小編並沒有將代碼完全貼出來,要是每條線都貼出來就太麻煩了,大家可以去下載源碼(源碼地址已經給出),讀者可以在調試項目的時候可以加深理解。