Shiro + CAS + (Spring) 集成
2017-06-21 00:00
381 查看
1 CAS 简介
CAS 全称为 Central Authentication Service(中央认证服务),它是耶鲁大学发起的一个开源项目,为 Web 应用系统提供一种可靠的单点登录方式,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目,它具有以下特点:
CAS 是一款开源的企业级单点登录解决方案,为应用系统提供中央认证服务。
CAS 服务器是独立部署的 Web 应用,可运行在主流的 Web 容器上,例如:Tomcat、Jetty 等。
CAS 客户端支持许多不同语言开发的应用系统,包括:Java、.Net、PHP、Apache、Perl、Ruby 等。
2 下载 CAS 服务器
可以从 CAS 官网:http://www.jasig.org/cas 下载,这可能需要翻墙,如果你不太愿意翻墙的话,可以访问这个地址:http://downloads.jasig.org/cas/,同样可以下载。
下载 CAS 服务器最新版:cas-server-3.5.2-release.zip
解压程序包
复制 cas-server-3.5.2/modules/cas-server-webapp-3.5.2.war 到 Tomcat 的 webapps 目录下,并重命名为 ROOT.war。
在启动 Tomcat 之前,还需要做两件事情:
创建 CAS 密钥库
使 Tomcat 支持 HTTPS
3 创建密钥库
使用 JDK 的 keytool 命令生成密钥库(keystore),其实就是一份 keystore 文件,keystore 必须通过密码才能访问。
keystore 里包含了多个密钥对(keypair),每个 keypair 都有一个别名(alias),alias 必须保证唯一性,而且都有一个密码,有此可知,keystore 与 keypair 都有自己的密码。
JDK 也有自己的 keystore,位于 %JAVA_HOME%\jre\lib\security\cacerts,其密码就是 changeit,当然也可以通过 keytool 命令来修改。
我们首先生成 keypair 及其存放 keypair 的 keystore,然后从 keystore 里导出证书,最后将证书导入 JDK 的 keystore 里,Tomcat 在运行时就会自动读取 JDK 的 keystore,以确保所部署的应用可以享受 HTTPS 协议(SSL 通道)带来的安全性。
3.1 生成 keypair
使用以下命令生成密钥对:
keytool -genkeypair -alias cas -keyalg RSA -storepass changeit
生成要注意,第一个姓和名需要和你的项目用到的域名相同 比如我的 server.cas,其他的项随便写
默认情况下,生成的 keystore 就是用户目录下的 .keystore 文件。对于 Win8 而言,默认的用户目录为 C:\Users\ 用户名。
以上命令执行完毕后,会在用户目录下生成一份 .keystore 文件(如果以前不存在该文件的话),其中包括一个 keypair。
注意:
为了简化操作,建议 keystore 与 keypair 的密码相同,且均为 changeit。
提示“您的名字与姓氏是什么?”,这里需要输入一个域名,例如:www.xxx.com,本例中输入 cas 需要在 hosts 文件中做如下映射:
127.0.0.1 cas
还有几条常用的 keytool 命令:
查看 keypair:
keytool -list -storepass changeit
删除 keypair:
keytool -delete -alias <别名> -storepass changeit
3.2 从 keystore 中导出证书
使用以下命令导出证书:
keytool -exportcert -alias cas -file cas.crt -storepass changeit
生成的证书文件为 cas.crt,位于运行该命令所在的当前目录下。
可双击该证书文件,将该证书安装到“受信任的根证书颁发机构”中,这样在浏览器中使用 HTTPS 协议访问时才不会出现一个红色的叉叉。
3.3 导入证书到 JVM 中
使用以下命令导入证书到 JVM 的 keystore 中:
keytool -importcert -alias cas -file cas.crt -keystore "%JAVA_HOME%\jre\lib\security\cacerts" -storepass changeit -noprompt
这里注意单独安装的JRE和JDK中的JRE
默认情况下,Tomcat 将读取 JVM 中的密钥库,而不是用户目录下的 .keystore 密钥库,当然也可以配置 Tomcat 使其读取指定的密钥库。
注意:
在执行以上命令前,必须需要保证 cacerts 文件对当前用户有写权限。
JDK 的 keystore 的密码必须为 changeit,这样 Tomcat 无需做任何配置就能访问。
4 使 Tomcat 支持 HTTPS
打开 Tomcat 的 conf/server.xml 文件。
修改以下配置:
将以上配置中的 SSLEngine 改为 off,默认为 on。
禁用 HTTP 8080 端口,开启 HTTPS 8443 端口,禁用 AJP 8009 端口,以确保只能通过 HTTPS 协议访问 CAS 服务器。
若将 HTTPS 端口号配置为 443,则可以使用无端口方式发送 HTTPS 请求。
5 运行 CAS 服务器
启动部署了 CAS 服务器的 Tomcat,并使用以下地址访问 CAS 登录页面:
https://cas:8443/login
一定要使用域名 cas 来访问,实际上 cas 指向了 127.0.0.1(需要在本机的 hosts 中进行配置)。
CAS 默认采用了最简单的认证,即用户名与密码必须有,但两者必须相同,也可对 CAS 做个性化认证配置。
可以使用如下 URL 注销 CAS:
https://cas:8443/logout
6 经验小结
这里只是个人总结,我也是初学者,我在学习的过程中这些内容网上查找资料没有合适的说明,导致走了很多弯路,希望我的情况记录可以帮助和我有相同问题的朋友。
下面贴出我的spring-shiro -config.xml
tip: 以下是我学习遇到的问题,希望自己记住同时给大家参考
① 请注意我在下边XML配置中标红的地方(算了,挪到os不能标红了,对应下面的代码块看吧),
<!-- 验证 tikict向 cas服务器发送验证请求用的,cas服务端前缀 -->
<property name="casServerUrlPrefix" value="https://server.cas:8443/cas/"/>
<!-- 应用服务地址, cas tikect这个要和回调地址一样,shiro会验证两个地址是否相同 -->
<property name="casService" value="https://cli1.cas:8443/cli1/oauth"/>
<!-- cas server登陆请求地址后面一定要跟回调地址,要不然是回不来的 -->
<property name="loginUrl"
value="https://server.cas:8443/cas/login?https://cli1.cas:8443/cli1/oauth"/>
这三个请求地址不要弄混,本人在做集成配置的时候,这三个配置把我折磨的不行,可能别人的文章中跟我的有出入,也许是使用环境问题,我这里使用的TOMCAT,应用程序客户端和cas服务端一起发布的,所以一定要有 /cas/这样的项目路径,有的文章中说用 ip+port,这个说法是在你项目根路径就是 “/”的情况下试用,实际上是不适用所有情况的
② SSL证书问题,我是不太了解SSL的,但是本文上边的SSL生成没有问题,只需要CAS服务端生成一个加入JRE就行了,注意是JRE,如果你同时安装了JDK和JRE要分清楚,只安装JDK好说,只有一个JRE。
③ 就是这个登陆流程的问题,稍微说一下(本项目的情况下 Spring、Shiro、CAS):
客户端请求应用,shiro过滤器请求,如果需要验证,会根据设置的loginUrl
请求CAS服务器,用户在CAS服务器进行身份验证,不成功没什么好说的,如果成功,CAS服务器会将请求重定向到应用服务器(这个重定向地址,是你设置的loginUrl的service参数,这个参数中你应该加上shrio的过滤器key,这个下边的配置中我标出来了),带上一个ticket,应用服务器接到这个重定向请求后,由于含有过滤器 key ,所以会被 CasFilter过滤,CasRealm会对这个ticket进行验证,根据 casServerUrlPrefix 和 ticket 以及回调地址 casService 我写到这突然觉得这个是在这里用的,只是猜测没有验证,但拼接请求后面肯定有回调函数,这个我看过有保证,然后CAS服务器会对ticket进行验证,发回结果。
下面的图还是很清晰的
CAS 全称为 Central Authentication Service(中央认证服务),它是耶鲁大学发起的一个开源项目,为 Web 应用系统提供一种可靠的单点登录方式,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目,它具有以下特点:
CAS 是一款开源的企业级单点登录解决方案,为应用系统提供中央认证服务。
CAS 服务器是独立部署的 Web 应用,可运行在主流的 Web 容器上,例如:Tomcat、Jetty 等。
CAS 客户端支持许多不同语言开发的应用系统,包括:Java、.Net、PHP、Apache、Perl、Ruby 等。
2 下载 CAS 服务器
可以从 CAS 官网:http://www.jasig.org/cas 下载,这可能需要翻墙,如果你不太愿意翻墙的话,可以访问这个地址:http://downloads.jasig.org/cas/,同样可以下载。
下载 CAS 服务器最新版:cas-server-3.5.2-release.zip
解压程序包
复制 cas-server-3.5.2/modules/cas-server-webapp-3.5.2.war 到 Tomcat 的 webapps 目录下,并重命名为 ROOT.war。
在启动 Tomcat 之前,还需要做两件事情:
创建 CAS 密钥库
使 Tomcat 支持 HTTPS
3 创建密钥库
使用 JDK 的 keytool 命令生成密钥库(keystore),其实就是一份 keystore 文件,keystore 必须通过密码才能访问。
keystore 里包含了多个密钥对(keypair),每个 keypair 都有一个别名(alias),alias 必须保证唯一性,而且都有一个密码,有此可知,keystore 与 keypair 都有自己的密码。
JDK 也有自己的 keystore,位于 %JAVA_HOME%\jre\lib\security\cacerts,其密码就是 changeit,当然也可以通过 keytool 命令来修改。
我们首先生成 keypair 及其存放 keypair 的 keystore,然后从 keystore 里导出证书,最后将证书导入 JDK 的 keystore 里,Tomcat 在运行时就会自动读取 JDK 的 keystore,以确保所部署的应用可以享受 HTTPS 协议(SSL 通道)带来的安全性。
3.1 生成 keypair
使用以下命令生成密钥对:
keytool -genkeypair -alias cas -keyalg RSA -storepass changeit
生成要注意,第一个姓和名需要和你的项目用到的域名相同 比如我的 server.cas,其他的项随便写
默认情况下,生成的 keystore 就是用户目录下的 .keystore 文件。对于 Win8 而言,默认的用户目录为 C:\Users\ 用户名。
以上命令执行完毕后,会在用户目录下生成一份 .keystore 文件(如果以前不存在该文件的话),其中包括一个 keypair。
注意:
为了简化操作,建议 keystore 与 keypair 的密码相同,且均为 changeit。
提示“您的名字与姓氏是什么?”,这里需要输入一个域名,例如:www.xxx.com,本例中输入 cas 需要在 hosts 文件中做如下映射:
127.0.0.1 cas
还有几条常用的 keytool 命令:
查看 keypair:
keytool -list -storepass changeit
删除 keypair:
keytool -delete -alias <别名> -storepass changeit
3.2 从 keystore 中导出证书
使用以下命令导出证书:
keytool -exportcert -alias cas -file cas.crt -storepass changeit
生成的证书文件为 cas.crt,位于运行该命令所在的当前目录下。
可双击该证书文件,将该证书安装到“受信任的根证书颁发机构”中,这样在浏览器中使用 HTTPS 协议访问时才不会出现一个红色的叉叉。
3.3 导入证书到 JVM 中
使用以下命令导入证书到 JVM 的 keystore 中:
keytool -importcert -alias cas -file cas.crt -keystore "%JAVA_HOME%\jre\lib\security\cacerts" -storepass changeit -noprompt
这里注意单独安装的JRE和JDK中的JRE
默认情况下,Tomcat 将读取 JVM 中的密钥库,而不是用户目录下的 .keystore 密钥库,当然也可以配置 Tomcat 使其读取指定的密钥库。
注意:
在执行以上命令前,必须需要保证 cacerts 文件对当前用户有写权限。
JDK 的 keystore 的密码必须为 changeit,这样 Tomcat 无需做任何配置就能访问。
4 使 Tomcat 支持 HTTPS
打开 Tomcat 的 conf/server.xml 文件。
修改以下配置:
... <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" /> ...
将以上配置中的 SSLEngine 改为 off,默认为 on。
... <!--<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="18443" />--> ... <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" /> ... <!--<Connector port="8009" protocol="AJP/1.3" redirectPort="18443" />--> ...
禁用 HTTP 8080 端口,开启 HTTPS 8443 端口,禁用 AJP 8009 端口,以确保只能通过 HTTPS 协议访问 CAS 服务器。
若将 HTTPS 端口号配置为 443,则可以使用无端口方式发送 HTTPS 请求。
5 运行 CAS 服务器
启动部署了 CAS 服务器的 Tomcat,并使用以下地址访问 CAS 登录页面:
https://cas:8443/login
一定要使用域名 cas 来访问,实际上 cas 指向了 127.0.0.1(需要在本机的 hosts 中进行配置)。
CAS 默认采用了最简单的认证,即用户名与密码必须有,但两者必须相同,也可对 CAS 做个性化认证配置。
可以使用如下 URL 注销 CAS:
https://cas:8443/logout
6 经验小结
这里只是个人总结,我也是初学者,我在学习的过程中这些内容网上查找资料没有合适的说明,导致走了很多弯路,希望我的情况记录可以帮助和我有相同问题的朋友。
下面贴出我的spring-shiro -config.xml
tip: 以下是我学习遇到的问题,希望自己记住同时给大家参考
① 请注意我在下边XML配置中标红的地方(算了,挪到os不能标红了,对应下面的代码块看吧),
<!-- 验证 tikict向 cas服务器发送验证请求用的,cas服务端前缀 -->
<property name="casServerUrlPrefix" value="https://server.cas:8443/cas/"/>
<!-- 应用服务地址, cas tikect这个要和回调地址一样,shiro会验证两个地址是否相同 -->
<property name="casService" value="https://cli1.cas:8443/cli1/oauth"/>
<!-- cas server登陆请求地址后面一定要跟回调地址,要不然是回不来的 -->
<property name="loginUrl"
value="https://server.cas:8443/cas/login?https://cli1.cas:8443/cli1/oauth"/>
这三个请求地址不要弄混,本人在做集成配置的时候,这三个配置把我折磨的不行,可能别人的文章中跟我的有出入,也许是使用环境问题,我这里使用的TOMCAT,应用程序客户端和cas服务端一起发布的,所以一定要有 /cas/这样的项目路径,有的文章中说用 ip+port,这个说法是在你项目根路径就是 “/”的情况下试用,实际上是不适用所有情况的
② SSL证书问题,我是不太了解SSL的,但是本文上边的SSL生成没有问题,只需要CAS服务端生成一个加入JRE就行了,注意是JRE,如果你同时安装了JDK和JRE要分清楚,只安装JDK好说,只有一个JRE。
③ 就是这个登陆流程的问题,稍微说一下(本项目的情况下 Spring、Shiro、CAS):
客户端请求应用,shiro过滤器请求,如果需要验证,会根据设置的loginUrl
请求CAS服务器,用户在CAS服务器进行身份验证,不成功没什么好说的,如果成功,CAS服务器会将请求重定向到应用服务器(这个重定向地址,是你设置的loginUrl的service参数,这个参数中你应该加上shrio的过滤器key,这个下边的配置中我标出来了),带上一个ticket,应用服务器接到这个重定向请求后,由于含有过滤器 key ,所以会被 CasFilter过滤,CasRealm会对这个ticket进行验证,根据 casServerUrlPrefix 和 ticket 以及回调地址 casService 我写到这突然觉得这个是在这里用的,只是猜测没有验证,但拼接请求后面肯定有回调函数,这个我看过有保证,然后CAS服务器会对ticket进行验证,发回结果。
下面的图还是很清晰的
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 缓存管理器 使用 Ehcache实现 --> <bean id="cacheManager" class="com.shige.mall.shiro.cacahe.ShiroMemcachedManager"/> <!-- 凭证匹配器 --> <bean id="credentialsMatcher" class="com.shige.mall.shiro.credentials.RetryLimitHashedCredentialsMatcher"> <constructor-arg ref="cacheManager"/> <property name="hashAlgorithmName" value="md5"/> <property name="hashIterations" value="1"/> <property name="storedCredentialsHexEncoded" value="true"/> </bean> <!-- session Id Generator --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- session Id Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="jsid"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="1800000"/> </bean> <!-- remember me start--> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="892000"/> </bean> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <!-- 看了源码这个长度需要 16 ,22,32字节,但是后边还有一个判断,我做的时候只有16长度的 OK,坑死我,这个仅供参考 --> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('f22*^*)(*BN)(I*oN3*d)M(*8u*43*4s6*7df')}"/> <property name="cookie" ref="rememberMeCookie"/> </bean> <!-- remember me end--> <!-- 会话 DAO --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="sessionIdGenerator" ref="sessionIdGenerator"/> <!-- 根据源码来看,这里不注入的话会构造匿名实现一个 manager 创建的 cache是 ConcurrentHashMap --> <property name="cacheManager" ref="cacheManager"/> </bean> <!-- 会话验证调度器 --> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> <property name="sessionValidationInterval" value="1800000"/> <property name="sessionManager" ref="sessionManager"/> </bean> <!-- session listener --> <bean id="sessionOnlinNumListener" class="com.shige.mall.shiro.listener.OnlineNumberListener"/> <!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <!-- 这块换成 memcached了 应当弄一弄 --> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/> <property name="sessionDAO" ref="sessionDAO"/> <property name="sessionIdCookieEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/> <property name="sessionListeners" ref="sessionOnlinNumListener"/> </bean> <!-- Realm实现 --> <bean id="casRealm" class="org.apache.shiro.cas.CasRealm"> <property name="cachingEnabled" value="true"/> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> <property name="defaultRoles" value="admin,user"/> <property name="defaultPermissions" value="user:create,user:update"/> <property name="roleAttributeNames" value="roles"/> <property name="permissionAttributeNames" value="permissions"/> <!-- 验证 tikict向 cas服务器发送验证请求用的,cas服务端前缀 --> <property name="casServerUrlPrefix" value="https://server.cas:8443/cas/"/> <!-- 应用服务地址, cas tikect这个要和回调地址一样,shiro会验证两个地址是否相同 --> <property name="casService" value="https://cli1.cas:8443/cli1/oauth"/> </bean> <bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/> <!-- 验证服务器端返回的 CAS Service Ticket --> <bean id="casFilter" class="org.apache.shiro.cas.CasFilter"> <property name="failureUrl" value="/casFailure.jsp"/> </bean> <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="index.jsp" /> </bean> <!-- 基于 Form表单的身份验证过滤器 --> <!--<bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <property name="loginUrl" valulogins.jsp.jsp"/> </bean>--> <!-- Shiro的 Web过滤器 shiro实现的 filter多条件都是 &&关系,如果想要 || 可自定义 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!-- cas server登陆请求地址后面一定要跟回调地址,要不然是回不来的 --> <property name="loginUrl" value="https://server.cas:8443/cas/login?https://cli1.cas:8443/cli1/oauth"/> <property name="successUrl" value="/index.jsp"/> <property name="unauthorizedUrl" value="/unauthorized.jsp"/> <property name="filters"> <map> <entry key="cas" value-ref="casFilter"/> 过滤器对应的KEY </map> </property> <property name="filterChainDefinitions"> <value> <!-- user --> <!--/user/passwordChange = anon /user/newUserInfo = cas /user/loginInfo = user <!– goods –> /goods/** = anon /management/goods/** = roles[merchant] <!– cart –> /cart/** = cas <!– order –> /order/** = cas <!– address –> /ReceiverAddress/** = cas <!– category –> /management/category/** = roles[merchant] <!– order –> /order/** = cas /Management/Order = roles[merchant]--> /casFailure.jsp=anon /oauth*=cas /**=user </value> </property> </bean> <!-- 安全管理器的超级父接口是 SessionManager --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="casRealm"/> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> <property name="rememberMeManager" ref="rememberMeManager"/> <property name="subjectFactory" ref="casSubjectFactory"/> </bean> <!-- Shiro生命周期处理器 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 相当于调用 SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <!-- shiro注解 --> <bean class=" org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> </beans>
相关文章推荐
- 单点登录cas与权限管理框架shiro集成------spring项目方式
- 单点登录CAS与权限管理框架Shiro集成------Spring项目方式
- Spring Boot 集成Shiro和CAS
- Spring Boot 集成Shiro和CAS
- Spring Boot 集成Shiro和CAS
- 单点登录cas与权限管理框架shiro集成-spring项目方式
- 七、spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
- spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
- Spring Boot 集成Shiro和CAS
- 十一、Spring Boot 集成Shiro和CAS
- [原]CAS和Shiro在spring中集成
- CAS和Shiro在spring中集成
- Spring Shiro CAS 客户端集成配置
- CAS和Shiro在spring中集成+Hibernate缓存优化
- Spring Boot 集成Shiro和CAS
- CAS和Shiro在spring中集成
- CAS和Shiro在spring中集成
- Shiro学习总结(10)——Spring集成Shiro
- Apache Shiro 集成-Cas
- Apache Shiro 集成-Cas