一、单点登录(SSO,Single Sign On)整合
目前计划接入统一门户的所有业务系统均为基于JavaEE技术的B/S架构系统。由于统一门户的单点登录技术选用的是JA-SIG组织开发的Cas Server,故为了与Cas Server进行无缝整合,各业务系统选用的技术依然是由JA-SIG组织开发的Cas Client。
根据各业务系统服务端技术架构的不同,现提供如下2种整合方式:
1. 在web.xml中配置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>http://CAS_SERVER/cas-server/login</param-value></init-param><init-param><param-name>serverName</param-name><param-value>http://CAS_CLIENT</param-value></init-param>
</filter>
<filter-mapping><filter-name>CAS Authentication Filter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

说明:
<1> casServerLoginUrl - CasServer的地址。其中cas-server为CasServer的应用名,对于所有接入统一门户的系统来说,其值应为ac。例如:http://172.16.49.243:7001/ac/login
<2> serverName - 本业务系统的IP+端口。例如:http://localhost:8080
<3> 当在CasServer端验证完毕后,CasServer会重定向到业务系统,重定向的URL是serverName+业务系统的名称。例如:http://localhost:8080/bxloan。业务系统需为此URL映射提供服务端处理逻辑,以便接收由CasServer认证后的用户工号。
<4> 配置serverName后,由CasServer认证后的重定向URL只能是系统根路径。若需自定义认证后的重定向URL,需要删除serverName的init-param,改用service。在service中指定认证后的重定向URL。例如:http://localhost:8080/bxloan/cas
<5> 如想要认证过程中放过某些url(如webservices,/services/*),可以使用ignorePattern或ignoreUrlPatternType。

<!-- 使用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>http://CAS_SERVER/cas-server</param-value></init-param><init-param><param-name>serverName</param-name><param-value>http://CAS_CLIENT</param-value></init-param>
</filter>
<filter-mapping><filter-name>CAS Validation Filter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

说明:
<1> casServerUrlPrefix - CasServer的URL前缀。对于统一门户来说,应为:http://172.16.49.243:7001/ac
<2> serverName -本业务系统的IP+端口。例如:http://localhost:8080。此URL会传给CAS服务端用以票据校验。

<!-- 包装了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.http.HttpServletRequest.getRemoteUser() 来获取到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中获取用户。获取方法:AssertionHolder.getAssertion()
.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><version>${commons-codec.version}</version>
</dependency>
<!-- SECURITY end -->

2) web.xml
<1> 让Spring加载shiro配置文件

<context-param><param-name>contextConfigLocation</param-name><param-value>classpath*:applicationContext.xmlclasspath*:applicationContext-shiro.xml</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) applicationContext-shiro.xml

<?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-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.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="casRealm" /><property name="cacheManager" ref="shiroEhcacheManager" /><property name="subjectFactory" ref="casSubjectFactory" /></bean><bean id="casRealm" class="com.coamctech.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="classpath:ehcache-shiro.xml" /></bean><bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory" /><bean id="casFilter" class="com.coamctech.portal.web.security.MyCasFilter" /><!-- 相当于调用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 id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>

4) applicatoin.properties
#cas settings
ac.host=http://172.16.49.243:7001
local.host=http://localhost:8080

#shiro-cas settings
shiro.loginUrl=${cas.casServerUrlPrefix}?service=${cas.casService}
shiro.successUrl=/
cas.casServerUrlPrefix=${ac.host}/ac
cas.casService=${local.host}/portal/cas
此为applicationContext-shiro.xml中占位符的内容。
在applicatonContext-shiro中,有两个绿色的bean不是来自Shiro或Spring。这两个bean分别对框架提供的默认功能提供了一些扩展。以下内容会涉及Shiro的知识,请先了解Shiro。
5) 扩展CasRealm

package com.coamctech.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;import com.coamctech.portal.entity.User;
import com.coamctech.portal.service.usermng.UserMngService;public class MyCasRealm extends CasRealm {private static final Logger logger = LoggerFactory.getLogger(MyCasRealm.class);private UserMngService userMngService;public void setUserMngService(UserMngService userMngService) {this.userMngService = userMngService;}/*** 认证*/@SuppressWarnings("unchecked")@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {SimpleAuthenticationInfo info = (SimpleAuthenticationInfo) super.doGetAuthenticationInfo(token);PrincipalCollection principalCollection = info.getPrincipals();List<Object> listPrincipals = principalCollection.asList();String username = (String) listPrincipals.get(0);logger.info("cas-username:" + username);Map<String, String> attributes = (Map<String, String>) listPrincipals.get(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 = userMngService.getByUsername(username);ShiroUser shiroUser = new ShiroUser();BeanUtils.copyProperties(user, shiroUser);return shiroUser;}/*** 鉴权*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return super.doGetAuthorizationInfo(principals);}}

Shiro的Realm用来获取用户相关信息。CasRealm的doGetAuthenticationInfo()返回的认证信息(AuthenticationInfo)中只保存了由CasServer传过来的用户工号。那么,我们在业务代码(或许是某个Controller)中通过SecurityUtils.getSubject().getPrincipal() 获取到的就只是这个工号。
如果想在每次调用 SecurityUtils.getSubject().getPrincipal() 时获取完整的当前用户信息,则需要在获取到用户工号后,根据用户工号查询业务系统中的用户表,加载用户相关信息,然后再保存至认证信息(AuthenticationInfo)中。
也即MyCasRealm重写doGetAuthenticationInfo() 中完成的过程。

6) 扩展CasFilter

package com.coamctech.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 = MyCasFilter.class.getName() + ".casShiroLoginFailure";@Overrideprotected boolean onLoginFailure(AuthenticationToken token, AuthenticationException ae,ServletRequest request, ServletResponse response) {String className = ae.getClass().getName();request.setAttribute(ERROR_KEY_ATTRIBUTE_NAME, className);return true;}}

Shiro在认证过程中如果出现异常,则会将异常交给开发人员自己处理。CasFilter在onLoginFailure()中的默认处理是,重定向到failureUrl,而failureUrl则指向某个页面。但遗憾的,是在failureUrl指向的页面中,并不能获取到异常的详细信息(因为Shiro并没把异常信息放进去,所以我们当然获取不到)。从而不能根据异常的类型,显示不同的信息。
为此,MyCasFilter重写了onLoginFailure() ,将异常信息放在request scope中,最后返回return true表示过滤链会继续执行。即在applicationContext-shiro.xml配置的cas.casService(http://localhost:8080/portal/cas)会继续执行。那么,我们要在业务代码中加入对/cas的映射,从request scope取出异常名,然后根据不同的异常名,做不同的逻辑处理。
二、单点登出(SSO,Single Sign Out)
由于所有业务集成接入统一门户后,即只有一个登入入口,那么也需要只有一个登出出口。故在统一门户或各业务系统(如果有需要)中需要提供单点登出功能。
JA-SIG Cas Client已提供了单点登出功能,实现方式只是在web.xml这配置1个过滤器和1个监听器就可以了。

<!-- 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>

请使SingleSignOutFilter先与其它过滤器执行。
三、业务系统的进一步改造
业务系统的进一步改造主要有以下三点:

1. 提供可靠的安全机制,不可让用户认证绕过统一门户
在统一门户中,用户登入后,会根据用户的权限列出能够访问的系统。通常,用户不会具有所有系统的访问权限。
由于各个业务系统都会接入认证中心,那么就可能会出现绕过统一门户的权限限制,直接登入业务系统的情况。一个可能的情境是:业务系统接入认证中心(ac)后,用户先在ac完成认证,然后直接输入业务系统URL,根据CAS SSO的机制,此时依然可直接登录。
因此,业务系统必须加入判断,判断用户登入时必须是从统一门户登录过来的才可以,否则不予登入。
2. 屏蔽登录入口,用户和机构维护功能
统一门户系统启用后,所有接入门户的业务系统登录入口都要统一到门户系统。因此,各业务系统无需也不能再提供系统登录入口。
另外,由于用户和机构数据也集中在门户统一维护,业务系统还需屏蔽掉用户和机构维护功能。或者保留维护功能,但由统一门户发送过来的字段不可修改。
3. 提供WebServices接口,用以与统一门户同步用户和机构数据
统一门户系统启用后,所有的用户和机构数据都在统一门户系统中进行维护。所有业务系统中的用户和机构数据需要与统一门户系统保持统一。
为此各业务系统必须提供WebServices接口供统一门户系统调用,用以当统一门户系统中对用户和机构数据进行维护后,能够调用各业务系统的WebServices接口完成数据同步。
各业务系统提供的WebServices接口在接收到统一门户发送过来的用户或机构后,需根据自己系统中的用户表和机构表结构,组织好数据,进行保存。同步接口定义如下:

1). 同步用户:
public String syncUser(String jsonUser, String operation)

jsonUser为门户的用户对象的json形式,各字段为:
private Integer id;
private String loginName;// 登录账号(员工工号)
private String password; // 密码
private String name; // 用户姓名
private String mobile; // 手机号
private String address; // 地址
private String email; // 邮箱
private String state; // 用户状态:1-使用,2-禁用
private String idCard; // 身份证
private String phone; // 固定电话
private Integer createPerson; // 创建人
private Date createDate; // 创建日期
private Date expireDate; // 失效时间
private String allowIps; // 允许ips
private Integer lastModifiedUser; // 最后修改人
private Date lastModifiedDate; // 最后修改日期
private Date lastLoginDate; // 最后登录日期
private String lastLoginIp; // 最后登录IP
private Integer tenantId; // 租户ID
private String userLevel; // 用户级别
private Integer orgId; // 机构ID

operation: save-保存或新增,delete-删除

返回值为json串,结构如下
private Boolean success; // 是否成功:成功-true,失败-false
private String msg; // 消息:"xx系统用户同步成功","小贷系统用户同步失败"
private Object data; // 数据
例如:{success: true,msg: "xx系统用户同步成功!", data: null}

2.同步机构
public String syncOrg(String jsonOrg, String operation)

jsonOrg为统一门户机构对象的json形式:
private Long id; // 机构ID
private Long parentId; // 上级机构
private String name; // 名称
private String manager; // 负责人
private String memo; // 备注
private String code; // 代码
private String type; // 机构类型:1-总公司,2-子公司,3-分公司,4-部门
private String state; // 状态:1-使用,2-禁用
private Long tenantId; // 租户ID
private Long createPerson; // 创建人
private Date createDate; // 创建时间
private Long lastModifiedUser; // 最近修改人
private Date lastModifiedDate; // 最近修改时间
private String bank; // 开户行名称
private String accountNumber; // 开户行账号
private Date foundingDate; // 成立时间
private Double registeredCapital; // 注册资本
private String phone; // 联系电话
private String formerName; // 曾用名
private String address; // 地址
private String zipcode; // 邮编
private String businessLicense;//营业执照号

operation: save-保存或新增,delete-删除

返回值为json串,结构如下
private Boolean success; // 是否成功:成功-true,失败-false
private String msg; // 消息:"xx系统机构同步成功!" "小贷系统机构同步失败!"
private Object data; // 数据
例如:{success: true, msg: "xx系统机构同步成功!", data: null}
参考资料
[1] https://wiki.jasig.org/display/CASC/CAS+Client+for+Java+3.1
[2] https://wiki.jasig.org/display/CASC/Configuring+the+Jasig+CAS+Client+for+Java+in+the+web.xml
[3] http://shiro.apache.org/cas.html
[4] http://jinnianshilongnian.iteye.com/blog/2036730
[5] https://wiki.jasig.org/display/CASC/Configuring+Single+Sign+Out
[6] http://jasig.github.io/cas/4.0.0/index.html

转载于:https://www.cnblogs.com/xyhero/p/9348654.html

统一门户与业务系统的sso整合技术方案(单点登录)相关推荐

  1. 你真的了解单点登录(SSO)吗? 单点登录实现方式

    在程序开发中,特别是网站类开发,会接触到单点登录(SSO),什么是单点登录?单点登录(SSO)有什么用?下面就来详细介绍一下. 1 单点登录 1.1 什么是单点登录 单点登录的英文名叫做:Single ...

  2. 不动产数据整合技术方案

    目录 存量数据整合 2 1.1目标与任务 2 1.1.1数据整合目标 2 1.1.2数据整合任务 2 1.2总体要求 4 1.3整合思路 5 1.4主要技术方法 9 1.4.1内业属性关联 9 1.4 ...

  3. CAS5.3服务器搭建及SpringBoot整合CAS实现单点登录

    CAS5.3服务器搭建及SpringBoot整合CAS实现单点登录 1.1 什么是单点登录 1.2 什么是CAS 1.3 CAS服务端部署 1.template下载 1.4 客户端搭建 1.1 什么是 ...

  4. 报告论文:汽车GPS调度系统车载终端设计技术方案

    汽车GPS调度系统车载终端设计技术方案 背景: 随着科技的发展,GPS民用化的趋势越来越让人期待.因为芯片小型化技术的日趋成熟,使得GPS芯片组在缩小体积或是降低耗电量等方面都有很大的突破. 这样,高 ...

  5. 【ChatGPT】ChatGPT 在电商用户运营业务中的应用、技术方案、带来的价值

    文章目录 [ChatGPT]ChatGPT 在电商用户运营业务中的应用.技术方案.带来的价值 一.摘要 二.引言 三.基本原理与架构 四.电商用户运营业务中的应用 4.1 用户画像 4.2 个性化推荐 ...

  6. 现代银行集中式业务系统及数据整合

    随着互联网和移动互联网的普及,互联网金融也日益进入人们的日常生活.当前互联网金融方兴未艾,各种新颖高效的金融产品层出不穷.随之而来的是日益激烈的竞争.在这次金融革新的大潮中,传统银行暂时处于相对保守的 ...

  7. sso 登出_SSO单点登录/登出系统实现

    先把源码贴出来,再慢慢讲解思路和原理以及实现方式 -->源代码1.0 整合了Mybatis +redis/redis集群二级缓存+cookie加密机制+token -->源代码2.1  密 ...

  8. (附源码)Spring Boot 框架整合 OAuth2 实现单点登录 SSO 详细完整源码教程!

    1.  前言 技术这东西吧,看别人写的好像很简单似的,到自己去写的时候就各种问题,"一看就会,一做就错".网上关于实现SSO的文章一大堆,但是当你真的照着写的时候就会发现根本不是那 ...

  9. SSO - 我们为何需要单点登录系统

    SSO,Single Sign On,也就是单点登录,保证一个账户在多个系统上实现单一用户的登录 现在随着网站的壮大,很多服务会进行拆分,会做SOA服务,会使用dubbo做微服务,或者简单的小型分布式 ...

最新文章

  1. C和C++混合编程的Makefile的编写!
  2. es6 name属性
  3. Android 网络交互之MD5为什么要加盐
  4. C++ 11 新特性: constexpr变量和constexpr函数
  5. IDA来远程调试Linux程序
  6. python语言打印菱形_Python打印菱形
  7. java 手机 上传图片_在手机端使用拍照功能上传图片的功能的解决文案
  8. SSH(Spring+Struts2+Hibernate)框架搭建步骤(含配置文件以及运行结果)
  9. 封装axios的接口请求数据方法
  10. 网校系统推荐eduline_网校系统的各项功能的用处
  11. Python可视化库matplotlib(基础整理)
  12. 使用java实现打印功能_java实现打印功能有没有比较好的方式?
  13. pyhton学习-1
  14. 23种设计模式-备忘录模式
  15. 网络操作系统具有哪些特征?
  16. [NOI 2010]超级钢琴
  17. 【工具】支付宝免费卡校验接口调用及常用银行简称整理
  18. game.php,game.php
  19. flying saucer做导PDF踩过的坑~
  20. iMeta | 德加合作揭示葛藤菌根真菌的遗传多样性和群落组成

热门文章

  1. 淮海工学院计算机网络期中考试,淮海工学院计算机基础知识和程序设计试卷集(共14份,含答案)...
  2. java多态 覆盖_java 多态 覆盖
  3. 网络营销常用的营销工具
  4. Photoshop脚本 旋转当前选区
  5. 如何管理二十八类型的员工
  6. 成功解决AttributeError: module ‘scipy.sparse‘ has no attribute ‘coo_array‘
  7. Linux - 第3节 - Linux进程概念
  8. MySQL数据库之全量+增量+二进制日志的备份与恢复
  9. 2024苏州大学计算机考研信息汇总
  10. 修改服务后 如何重启服务器,修改远程端口号后如何重启服务器