统⼀门户与业务系统的sso整合技术⽅案(单点登录)
⼀、单点登录(SSO,Single Sign On)整合
⽬前计划接⼊统⼀门户的所有业务系统均为基于JavaEE技术的B/S架构系统。由于统⼀门户的单点登录技术选⽤的是JA-SIG组织开发的Cas Server,故为了与Cas Server进⾏⽆缝整合,各业务系统选⽤的技术依然是由JA-SIG组织开发的Cas Client。
根据各业务系统服务端技术架构的不同,现提供如下2种整合⽅式:
1. 在l中配置4个过滤器
此⽅式适⽤于所有JavaWeb应⽤。
1) 所需jar
cas-client-core-3.3.3.jar
slf4j-api-1.7.1.jar
2) 配置4个过滤器(其中两个可选)
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>CAS_SERVER/cas-server/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>CAS_CLIENT</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 使⽤CAS 2.0协议校验票据 -->
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>CAS_SERVER/cas-server</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>CAS_CLIENT</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 包装了HttpServletRequest, 使得可以通过getRemoteUser()和getPrincipal()可以返回CAS相关⼊⼝ -->
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
说明:
<1> 可选配置。
<2> 配置后,可以使⽤javax.servlet.RemoteUser() 来获取到CasServer服务端发送过来的认证后的⽤户⼯号。<!-- 在ThreadLocal中放置应⽤中部分功能需要的访问的断⾔ -->
<filter>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
说明:
<1> 可选配置。
<2> 配置后,可以从与本地线程绑定的Assertion中获取⽤户。获取⽅法:Assertion()
.getPrincipal().getName()。
2. 与Spring+Shiro的配置
此⽅式适⽤于项⽬中已包含Spring+Shiro的项⽬。
1) Maven配置
Shiro 1.2.0之后的版本提供了与Cas Client的整合。
<!-- SECURITY begin -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>${ehcache.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
web端登录<version>${commons-codec.version}</version>
</dependency>
<!-- SECURITY end -->
2) l
<1> 让Spring加载shiro配置⽂件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:l
classpath*:l
</param-value>
</context-param>
<2> 以Spring的⽅式配置Shiro过滤器
<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>
3) l
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/schema/beans /schema/beans/spring-beans-3.2.xsd" default-lazy-init="true">
<description>Shiro安全配置</description>
<!-- Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="${shiro.loginUrl}"/>
<property name="successUrl" value="${shiro.successUrl}"/>
<property name="filters">
<map>
<entry key="cas" value-ref="casFilter"/>
</map>
</property>
<property name="filterChainDefinitions">
<value>
/static/** = anon
/cas = cas
/** = user
</value>
</property>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.DefaultWebSecurityManager">
<property name="realm" ref="casRealm"/>
<property name="cacheManager" ref="shiroEhcacheManager"/>
<property name="subjectFactory" ref="casSubjectFactory"/>
</bean>
<bean id="casRealm" class="amctech.portal.web.security.MyCasRealm" depends-on="userDao">
<property name="userMngService" ref="userMngService"/>
<property name="casServerUrlPrefix" value="${cas.casServerUrlPrefix}"/>
<property name="casService" value="${cas.casService}"/>
</bean>
<!-- ⽤户授权信息Cache, 采⽤EhCache -->
<bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="l"/>
</bean>
<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/>
<bean id="casFilter" class="amctech.portal.web.security.MyCasFilter"/>
<!-- 相当于调⽤SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.fig.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
<!-- Shiro⽣命周期处理器 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
amctech.portal.web.security;
import java.util.List;
import java.util.Map;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
ity.User;
amctech.portal.service.usermng.UserMngService;
public class MyCasRealm extends CasRealm {
private static final Logger logger = Logger(MyCasRealm.class);
private UserMngService userMngService;
public void setUserMngService(UserMngService userMngService) {
this.userMngService = userMngService;
}
/
**
* 认证
*/
@SuppressWarnings("unchecked")
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { SimpleAuthenticationInfo info = (SimpleAuthenticationInfo) super.doGetAuthenticationInfo(token);
PrincipalCollection principalCollection = Principals();
List<Object> listPrincipals = principalCollection.asList();
String username = (String) (0);
logger.info("cas-username:" + username);
Map<String, String> attributes = (Map<String, String>) (1);
ShiroUser shiroUser = getShiroUser(username);
List<Object> shiroPrincipals = CollectionUtils.asList(shiroUser, attributes);
principalCollection = new SimplePrincipalCollection(shiroPrincipals, getName());
info.setPrincipals(principalCollection);
return info;
}
private ShiroUser getShiroUser(String username) {
User user = ByUsername(username);
ShiroUser shiroUser = new ShiroUser();
return shiroUser;
}
/**
* 鉴权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return super.doGetAuthorizationInfo(principals);
}
}
Shiro的Realm⽤来获取⽤户相关信息。CasRealm的doGetAuthenticationInfo()返回的认证信息(Auth
enticationInfo)中只保存了由CasServer传过来的⽤户⼯号。那么,我们在业务代码(或许是某个Controller)中通过Subject().getPrincipal() 获取到的就只是这个⼯号。
如果想在每次调⽤ Subject().getPrincipal() 时获取完整的当前⽤户信息,则需要在获取到⽤户⼯号后,根据⽤户⼯号查询业务系统中的⽤户表,加载⽤户相关信息,然后再保存⾄认证信息(AuthenticationInfo)中。
也即MyCasRealm重写doGetAuthenticationInfo() 中完成的过程。
6) 扩展CasFilter
amctech.portal.web.security;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.cas.CasFilter;
public class MyCasFilter extends CasFilter {
public static final String ERROR_KEY_ATTRIBUTE_NAME = Name() + ".casShiroLoginFailure";
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException ae,
ServletRequest request, ServletResponse response) {
String className = ae.getClass().getName();
request.setAttribute(ERROR_KEY_ATTRIBUTE_NAME, className);
return true;
}
}
<!-- CAS Single Sign Out -->
<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>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论