cas shiro spring实现单点登录
来源:互联网 发布:上海争游网络首页 编辑:程序博客网 时间:2024/06/06 08:30
《SSO CAS单点系列》之 实操!轻松玩转SSO CAS就这么简单(相识篇)
《SSO CAS单点系列》之 实操!轻松玩转SSO CAS就这么简单(相遇篇)
这里贴出传送门,来自幕课网大神。讲了cas配置和cas的基本原理。
CAS
Github地址:https://github.com/apereo/cas/tags
war下载地址:http://mvnrepository.com/artifact/org.jasig.cas/cas-server-webapp
解压war包,新建一个工程,将解压后的war内容依次放入工程中。
结构如下:
这里只是使用和修改一下cas自带样式,不对源码做详细的研究,所以只是导出了工程文件。
deployerConfigContext.xml配置文件
默认通过配置文件管理授权登录账户
<bean id="primaryAuthenticationHandler" class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler"> <property name="users"> <map> <entry key="casuser" value="Mellon"/> </map> </property> </bean>
在实际应用中我们的账户管理多半在数据库中,cas也支持这种模式
这里使用4.0.0为例
<!-- cas自带 设置密码的加密方式,这里使用的是MD5加密 --> <bean id="passwordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" c:encodingAlgorithm="MD5" p:characterEncoding="UTF-8" /> <!-- 通过数据库验证身份,这个得自己去实现 --> <bean id="primaryAuthenticationHandler" class="com.distinct.cas.jdbc.QueryDatabaseAuthenticationHandler" p:dataSource-ref="dataSource" p:passwordEncoder-ref="passwordEncoder" p:sql="select top 1 UserPwd from Users where UserName=? " /><!-- 设置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"></property> <property name="url" value="jdbc:jtds:sqlserver://test:1433;DatabaseName=test"></property> <property name="username" value="test"></property> <property name="password" value="test123"></property> </bean>
我们看到QueryDatabaseAuthenticationHandler的源码
public class QueryDatabaseAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler{ @NotNull private String sql; protected final HandlerResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential) throws GeneralSecurityException, PreventedException { String username = credential.getUsername(); System.err.println("======= input username:(" + username + ")"); String encryptedPassword = getPasswordEncoder().encode(credential.getPassword()); System.err.println("======= input password:(" + encryptedPassword + ")"); System.out.println("======= sql:(" + this.sql + ")"); try { String dbPassword = (String)getJdbcTemplate().queryForObject(this.sql, String.class, new Object[] { username }); System.err.println("++++++ dbPassword:(" + dbPassword.trim() + ")"); if (!dbPassword.trim().equals(encryptedPassword)) { System.err.println("Password not match."); throw new FailedLoginException("Password does not match value on record."); } } catch (IncorrectResultSizeDataAccessException e) { if (e.getActualSize() == 0) { throw new AccountNotFoundException(username + " not found with SQL query"); } e.printStackTrace(); throw new FailedLoginException("Multiple records found for " + username); } catch (DataAccessException e) { e.printStackTrace(); throw new PreventedException("SQL exception while executing query for " + username, e); } return createHandlerResult(credential, new SimplePrincipal(username), null); } public void setSql(String sql) { this.sql = sql; }}
这里实际上在针对密码做比对,之后的cas版本代码可能有所变更,但是基本的原理都是一样的。
这里说明一下MD5自带加密方式加密出来的字符串是小写,我的测试库中是大写密码,那么自己继承处理一下
package com.yvan.cas.password;import java.security.MessageDigest;import org.jasig.cas.authentication.handler.PasswordEncoder;public class YvanCasPassword implements PasswordEncoder { @Override public String encode(String arg0) { return getMD5(arg0).toUpperCase(); } public static String getMD5(String message) { String md5str = ""; try { // 1 创建一个提供信息摘要算法的对象,初始化为md5算法对象 MessageDigest md = MessageDigest.getInstance("MD5"); // 2 将消息变成byte数组 byte[] input = message.getBytes(); // 3 计算后获得字节数组,这就是那128位了 byte[] buff = md.digest(input); // 4 把数组每一字节(一个字节占八位)换成16进制连成md5字符串 md5str = bytesToHex(buff); } catch (Exception e) { e.printStackTrace(); } return md5str; } /** * 二进制转十六进制 * * @param bytes * @return */ public static String bytesToHex(byte[] bytes) { StringBuffer md5str = new StringBuffer(); // 把数组每一字节换成16进制连成md5字符串 int digital; for (int i = 0; i < bytes.length; i++) { digital = bytes[i]; if (digital < 0) { digital += 256; } if (digital < 16) { md5str.append("0"); } md5str.append(Integer.toHexString(digital)); } return md5str.toString().toUpperCase(); }}
新的配置如下:
<!-- 自定义加密 --> <bean id="yvanPasswordEncoder" class="com.yvan.cas.password.YvanCasPassword"></bean> <!-- cas自带 设置密码的加密方式,这里使用的是MD5加密 --> <bean id="passwordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" c:encodingAlgorithm="MD5" p:characterEncoding="UTF-8" /> <!-- 通过数据库验证身份,这个得自己去实现 --> <bean id="primaryAuthenticationHandler" class="com.distinct.cas.jdbc.QueryDatabaseAuthenticationHandler" p:dataSource-ref="dataSource" p:passwordEncoder-ref="yvanPasswordEncoder" p:sql="select top 1 UserPwd from Users where UserName=? " />
授权成功后
默认超时时间
ticketExpirationPolicies.xml中配置如下:
<bean id="grantingTicketExpirationPolicy" class="org.jasig.cas.ticket.support.TicketGrantingTicketExpirationPolicy" p:maxTimeToLiveInSeconds="${tgt.maxTimeToLiveInSeconds:28800}" p:timeToKillInSeconds="${tgt.timeToKillInSeconds:7200}"/>
默认为两小时。
ps:cas提供了remember me的解决方案,需要修改配置。
具体参考:https://my.oschina.net/mashiguang/blog/71005
shiro+spring
这里缺省spring mvc的基本配置,列出重要的sso配置
web.xml配置
<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> <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>
spring.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-cas1 = casFilter /logout = logoutFilter /users/test = anon /users/** = user </value> </property> </bean> <bean id="casFilter" class="org.apache.shiro.cas.CasFilter"> <!-- 配置验证错误时的失败页面 --> <property name="failureUrl" value="${shiro.failureUrl}" /> <property name="successUrl" value="${shiro.successUrl}" /> </bean> <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <!-- 配置验证错误时的失败页面 --> <property name="redirectUrl" value="${shiro.logoutUrl}" /> </bean> <bean id="casRealm" class="com.yvan.shiro.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>
properties文件配置
#统一登录urlshiro.loginUrl=http://127.0.0.1:8080/cas/login?service=http://127.0.0.1:8080/shiroNode/shiro-cas1#统一登出urlshiro.logoutUrl=http://127.0.0.1:8080/cas/logout?service=http://127.0.0.1:8080/shiroNode/shiro-cas1#cas服务地址前缀shiro.cas.serverUrlPrefix=http://127.0.0.1:8080/cas#接收cas票据地址shiro.cas.service=http://127.0.0.1:8080/shiroNode/shiro-cas1shiro.failureUrl=/users/loginSuccessshiro.successUrl=/users/loginSuccess
这里着重说明一下接收票据的service url配置:
这里配置不是绝对的,是可以修改的,但是如果修改那么对应需要修改几个地方。
如现在的地址为:
shiro.cas.service=http://127.0.0.1:8080/shiroNode/sso-test
那么
shiro.loginUrl=http://127.0.0.1:8080/cas/login?service=http://127.0.0.1:8080/shiroNode/sso-test
shiro.logoutUrl=http://127.0.0.1:8080/cas/logout?service=http://127.0.0.1:8080/shiroNode/sso-test
<property name="filterChainDefinitions"> <value> <!-- 指定访问什么url交给casFilter处理 --> /sso-test = casFilter /logout = logoutFilter /users/test = anon /users/** = user </value> </property>
realm实现
public class UserRealm extends CasRealm { 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(); } return authorizationInfo; } /** * 1、CAS认证 ,验证用户身份 * 2、将用户基本信息设置到会话中 */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { AuthenticationInfo authc = super.doGetAuthenticationInfo(token); /*List<Object> list = authc.getPrincipals().asList(); for (Object object : list) { System.out.println((String)object.toString()); }*/ String account = (String) authc.getPrincipals().getPrimaryPrincipal(); SecurityUtils.getSubject().getSession().setAttribute("user", account); return authc; }}
cas默认返回用户名,也可以返回更多信息,具体参考如下地址:
http://blog.csdn.net/u012410733/article/details/51729791
- spring + shiro + cas 实现sso单点登录
- spring + shiro + cas 实现sso单点登录
- spring + shiro + cas 实现sso单点登录
- cas shiro spring实现单点登录
- spring + shiro + cas 实现sso单点登录
- Shiro & CAS 实现单点登录
- Shiro & CAS 实现单点登录
- shiro结合cas实现单点登录
- 基于SpringBoot Shiro CAS单点登录实现
- shiro-cas 单点登录
- spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
- shiro 集成cas单点登录
- 第三部分:shiro集成spring使用cas单点登录配置
- 第三部分:shiro集成spring使用cas单点登录配置
- Spring Security集成CAS实现单点登录
- Spring Security 4.0 CAS实现单点登录
- spring springmvc shiro 实现单点登录demo
- spring boot整合Shiro实现单点登录
- 在JDBC中 java项目 以及 web项目加载路径文件的异同
- Android DiskLruCache(磁盘缓存)
- 闭包的学习例子
- 编译ESP8266固件说明
- 运行循环和自动释放池关系
- cas shiro spring实现单点登录
- Android LruCache(内存缓存)
- 远程登录 Windows 上 Mysql 配置
- Android studio如何添加HttClient
- IOS 之iIOS11更新 导航返回按钮偏移的问题。。。。。
- 重建二叉树 (剑指Offer 第 4 题)
- SD卡文件权限
- SVN和MyEclipse集成
- 计算机网络知识点总结1:可靠数据传输原理