前言
小编最近正在优化权限框架,应对的需求是:在一个分布式系统中,要有单点登录功能,还得有集中的权限认证。于是技术选型就找到了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对象的中拥有的资源信息进行比对,检查用户是否有权限访问该资源。
小结
小编并没有将代码完全贴出来,要是每条线都贴出来就太麻烦了,大家可以去下载源码(源码地址已经给出),读者可以在调试项目的时候可以加深理解。