Shiro整合CAS
shiro是现在最为流行的权限认证管理框架,但是现在已经不再是最为传统的shiro处理处理了,因此此时的处理牵扯到了CAS实现认证的操作部分,所以对于shiro而言,它依然需要实现认证与授权检测,但是这个时候的认证应该交由CAS完成。
在现实的开发过程中,客户端是不可能直接访问CAS服务器的。WEB客户端其实就是CAS客户端,CAS客户端如果想和CAS服务器正常通讯,它就必须有一个证书。所以在整个处理流程里面就首先要有一个证书的操作配置。这个证书配置在JDK上,所以这个CAS客户端必须运行好配置好证书的JDK上。
我们这次测试模拟 web浏览器——>web服务器(CAS客户端)和 CAS客户端——>CAS服务器 使用的协议不一样,一个是http,一个是https。因为现在两边的协议不一样,你在整个过程中还需要对CAS服务器进行一次变革,才能让它支持HTTP的协议跳板。
(1)整合前准备
1. 需要在本地的windows系统的JDK里面导入服务器端证书
- 前提:已经准确地配置了JAVA_HOME环境属性
- 服务器端证书的所在路径:
D:\server.cer
- 认证授权库:
JAVA_HOME\jre\lib\security\cacerts
keytool -import -alias server -file d:\server.cer -keystore "%JAVA_HOME\jre\lib\security\cacerts%" -storepass changeit
- 列出全部的本地的密钥库:
keytool -list -keystore "%JAVA_HOME\jre\lib\security\cacerts%" -storepass changeit
搜索一下是否有cas.com
2. 修改cas的配置文件,让其支持http协议访问
vim /usr/local/tomcat/webapps/cas/WEB-INF/classes/services/HTTPSandIMAPS-10000001.json
默认只支持https
追加支持http
然后重新启动服务器。那么此时将支持协议访问的路径。
(2)实现CasRealm
2.1 导入shiro与cas整合的处理包开发包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>1.3.1</version>
</dependency>
2.2 修改数据库脚本
当前使用的数据表需要包含有角色、权限等信息
2.3 此时所有的查询内容都将交由CAS负责,而shiro只是负责角色与权限数据的获取
范例:定义一个MemberCasRealm
程序类,需要继承CasRealm
父类。
- 所有的处理都应该交由CAS负责完成,所以此时实际上的认证处理相当于接收CAS认证后的结果(票根);
-
doGetAuthenticationInfo
方法:此时接收的AuthenticationToken
对象实际上是CasToken
类型
public class MemberCasRealm extends CasRealm {
@Autowired
private MemberService memberService;
/**
* 用户身份认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 此时接收的AuthenticationToken对象实际上是CasToken类型
CasToken casToken = (CasToken)token; // 现在需要返回的是CAS认证标记
if(casToken==null){ // 如果现在没有返回token标记
return null; // 当前的登录失败
}
// CAS一定要返回给用户一个票根,所以需要取得这个票根的内容
String ticket = (String)casToken.getCredentials();
// 需要对票根的有效性进行验证
if(!StringUtils.hasText(ticket)){ // 票根验证失败
return null; // 当前的登录失败
}
// 如果现在票根验证的格式正确,那么需要进行票根的有效性验证
TicketValidator ticketValidator = super.ensureTicketValidator();
try {
// 首先需要针对于票根的CAS做一个验证处理
Assertion casAssertion = ticketValidator.validate(ticket,super.getCasService());
// 当验证处理完成之后,应该通过CAS取得用户信息
AttributePrincipal casPrincipal = casAssertion.getPrincipal();
String mid = casPrincipal.getName(); // 取出当前登录的用户名
// 取出用户名之后需要将所有的相关信息(包括CAS相关信息)一起进行一个列表的创建
List principals = CollectionUtils.asList(mid,casPrincipal.getAttributes());
PrincipalCollection principalCollection = new SimplePrincipalCollection();
return new SimpleAuthenticationInfo(principalCollection,ticket);
} catch (TicketValidationException e) {
e.printStackTrace();
}
return super.doGetAuthenticationInfo(token);
}
/**
* 用户授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String)principals.getPrimaryPrincipal();
SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();
try {
Map<String,Object> map = this.memberService.listAuthByMember(userName);
Set<String> allRoles = (Set<String>)map.get("allRoles");
Set<String> allActions = (Set<String>)map.get("allActions");
auth.setRoles(allRoles);
auth.setStringPermissions(allActions);
} catch (TicketValidationException e) {
e.printStackTrace();
}
return auth;
}
}
此时对于使用的Realm只有用户认证部分发生了变化,而角色和权限的操作依然像之前那样直接通过业务层读取完成。
(3)环境配置
3.1 修改database.propeties文件
db.driver=org.ght.mm.mysql.Driver
db.url=jdbc:mysql://192.168.122.204:3306/shriodb
db.user=root
db.password=root
3.2 修改spring-shiro.xml文件
修改当前的Realm使用类型
<!-- 配置Realm -->
<bean id="memberRealm" class="com.web.cas.MemberCasRealm"/>
3.3 配置CAS的访问路径
<!-- 配置Realm -->
<bean id="memberRealm" class="com.web.cas.MemberCasRealm">
<!--配置cas服务器的地址-->
<property name="casServerUrlPrefix" value="https://cas.com"/>
<!-- 客户端的回调地址设置,必须和下面的shiro-cas过滤器拦截的地址一致 -->
<property name="casService" value="http://shiro.com/shirodemo/shiro-cas"/>
</bean>
3.4 配置CAS的访问过滤器
service=cas客户端回调地址
<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
<!-- 登录失败后的访问路径,应该设置为cas.com访问 -->
<property name="failureUrl" value="https://cas.com/login/service=http://shiro.com/shirodemo/shiro-cas"/>
</bean>
3.5 配置CAS注销的访问过滤器
注销就不能再回到回调页面了(总不能注销了再回来吧),所以我们重定向到首页。
<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value="https://cas.com/logout?service=http://shiro.com/shirodemo/index.jsp"/>
</bean>
3.6 修改shiro过滤器
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!--出现错误之后的跳转路径的配置-->
<property name="loginUrl" value="https://cas.com/logout?service=http://shiro.com/shirodemo/shiro-cas"/>
<!--认证失败之后的跳转路径页面-->
<property name="unauthorizedUrl" value="/unauthUrl.action"/>
<!--登录成功之后的跳转访问路径-->
<property name="successUrl" value="/hello.action"/>
<property name="filters">
<map>
<entry key="casFilter" value-ref="casFilter"/>
<entry key="logoutFilter" value-ref="logout"/>
</map>
</property>
<property name="filterChainDefinitions">
<value>
/shiro-cas = casFilter
/loginUrl.action=authc
/*=anon
/message/**=authc
</value>
</property>
</bean>
3.7 修改hosts文件
所有的访问都是以域名的方式出现的,所以还需要修改hosts文件,追加域名
127.0.0.1 shiro.com
(4)测试
访问shiro.com的首页
输入用户名和密码,从控制台可以看到已经进行了登陆的认证:
登录之后访问需要授权的页面,后台会出现角色和权限的信息查询提示信息。
CAS配置Remember me
如果要想配置rememberMe的操作需要考虑到两个配置部分:shiro(客户端)、cas(认证端)
1. 修改applicationContext.xml文件,为其追加一个工厂类
<bean id="securityManager" class="com.vip.vpao.web.cas.VpaoVisSecurityManager">
<property name="subjectFactory" ref="sSubjectFactory"/>
<!--其他配置省略-->
</bean>
<!-- 如果要实现cas的remember me的功能,需要用到下面这个bean,并设置到securityManager的subjectFactory中 -->
<bean id="subjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/>
2. 修改deployerConfigContext.xml配置文件
对里面的认证管理器authenticationManager进行配置
<bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">
<constructor-arg>
<map>
<entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
<!-- <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> -->
<entry key-ref="dbAuthHandler" value-ref="primaryPrincipalResolver"/>
</map>
</constructor-arg>
<!-- 添加remember me配置-->
<property name="authenticationMetaDataPopulators">
<util:list>
<bean class="org.jasig.cas.extension.clearpass.CacheCredentialsMetaDataPopulator"
c:credentialCache-ref="encryptedMap" />
</util:list>
</property>
<property name="authenticationPolicy">
<bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" />
</property>
</bean>
3. 修改另外一个页面的配置文件:cas\WEB-INF\webflow\login\login-webflow.xml
找到viewLoginForm表单,里面加上rememberMe标签:
<view-state id="viewLoginForm" view="casLoginView" model="credential">
<binder>
<binding property="username" />
<binding property="password" />
<binding property="captcha" />
<binding property="rememberMe" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credential'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="validatorCaptcha">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credential)" />
</transition>
</view-state>
4. 修改“cas\WEB-INF\spring-configuration\ticketExpirationPolicies.xml”文件(票根过期的配置文件)
替换原有的grantingTicketExpirationPolicy的bean为如下内容:
<bean id="grantingTicketExpirationPolicy" class="org.jasig.cas.ticket.support.RememberMeDelegatingExpirationPolicy">
<property name="sessionExpirationPolicy">
<bean class="org.jasig.cas.ticket.support.TimeoutExpirationPolicy">
<constructor-arg index="0" value="XXXXXXXX" />
</bean>
</property>
<property name="rememberMeExpirationPolicy">
<bean class="org.jasig.cas.ticket.support.TimeoutExpirationPolicy">
<constructor-arg index="0" value="XXXXXXXX" />
</bean>
</property>
</bean>
其实就是修改ticket过期策略。
5. rememberMe需要找到cookie,所以需要修改“cas\WEB-INF\spring-configuration\ticketGrantingTicketCookieGenerator.xml”文件
在ticketGrantingTicketCookieGenerator的bean中增加 p:rememberMeMaxAge="7200000"
,设定rememberMe保存的最长时间。
要注意的是这里的7200000为秒数。并且要注意和上面 ticketExpirationPolicies.xml中设置的保持一致。
6. 此时对于记住我这个信息实际上还没有提示内容,所以需要修改一个资源文件
- 文件路径:cas\WEB-INF\classes\messages_zh_CN.properties
- 添加以下配置
\u8BB0\u4F4F\u6211是中文“记住我”的转码
7. 修改页面显示文件
- 文件路径:cas\WEB-INF\view\jsp\default\ui\casLoginView.jsp
8. 测试
网友评论