CAS二次开发记录

创建项目

下载cas4.1.10的源代码,里面有非常多的module,我们使用cas-server-webapp来作为模块进行二次开发。

自己创建一个项目,将cas-server-webapp拷贝相关文件过来,注意整理pom的依赖。

数据源的修改

我们这里数据源使用的是jndi的方式,所以修改 deployerConfigContext.xml  增加如下配置

1 <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 2 <property name="jndiName"><value>java:comp/env/jdbc/OracleXXXX</value></property> 3 </bean>

同时,在webapp/META-INF/context.xml中配置对应的数据源信息

1<?xml version="1.0" encoding="UTF-8"?> 2<Context> 3<Resource name="jdbc/OracleXXXX" 4 auth="Container" 5 type="javax.sql.DataSource" 6 maxActive="10" 7 maxIdle="5" 8 maxWait="1000" 9 logAbandoned="true" 10 username="XXXX" 11 password="XXXX" 12 driverClassName="oracle.jdbc.driver.OracleDriver" 13 url="jdbc:oracle:thin:@192.168.0.1:1521:xxxx"/> 14 15</Context>

考虑到数据的操作,我封装了一个DAO方法,顺便定义一下

1 <bean id="casDao" 2 class="com.xxx.xxx.sso.CasDao" 3 p:dataSource-ref="dataSource" />

接入系统的配置

哪些系统能够使用cas,默认的定义在

1 <bean id="serviceRegistryDao" class="org.jasig.cas.services.JsonServiceRegistryDao" 2 c:configDirectory="${service.registry.config.location:classpath:services}" />

cas支持4中接入方式的定义:

1、InMemoryServiceRegistryDaoImpl
2、JsonServiceRegistryDao
3、JpaServiceRegistryDaoImpl:
4、MongoServiceRegistryDao

考虑到实际的业务场景,这部分的数据,肯定是需要配置到数据库中的,而且能够自动刷新,支持新增新的service时,能够做到不停机。

所以我们需要自己去实现,定义如下

1<bean id="serviceRegistryDao" class="com.xxxx.xxxx.sso.DbServiceRegistryDaoImpl" 2 p:casDao-ref="casDao" /> 3 4public class DbServiceRegistryDaoImpl implements ServiceRegistryDao { 5 @NotNull 6 private CasDao casDao; 7 8 public DbServiceRegistryDaoImpl() { 9 } 10 11 public void setCasDao(CasDao casDao) { 12 this.casDao = casDao; 13 } 14 15 @Override 16 public RegisteredService save(RegisteredService registeredService) { 17 return null; 18 } 19 20 @Override 21 public boolean delete(RegisteredService registeredService) { 22 return false; 23 } 24 25 @Override 26 public List<RegisteredService> load() { 27 return casDao.findRegisteredService(); 28 } 29 30 @Override 31 public RegisteredService findServiceById(long l) { 32 return casDao.findRegisteredServiceByServiceId(l); 33 } 34}

我们定义一个类去继承ServiceRegistryDao  主要去实现load和findServiceById的方法,暂时不实现delete和save。

主要是从数据库获取数据  返回对应的对象

1 public List<RegisteredService> findRegisteredService() { 2 List<RegisteredService> registeredServices = jdbcTemplate.query("select * from T_SYSTEM ", 3 new Object[] {}, new int[] {}, new RowMapper<RegisteredService>() { 4 @Override 5 public RegisteredService mapRow(ResultSet rs, int rowNum) throws SQLException { 6 RegexRegisteredService registeredServices = new RegexRegisteredService(); 7 registeredServices.setServiceId("^"+rs.getString("redirect_uri")+".*"); 8 registeredServices.setName(rs.getString("systemname")); 9 registeredServices.setDescription(rs.getString("systemdes")); 10 registeredServices.setId(rs.getLong("SYSTEMID")); 11 List<String> allowedAttributes = new ArrayList<String>(); 12 allowedAttributes.add(rs.getString("systemcode")); 13 registeredServices 14 .setAttributeReleasePolicy(new ReturnAllowedAttributeReleasePolicy(allowedAttributes)); 15 return registeredServices; 16 } 17 }); 18 return registeredServices; 19 }

    RegisteredService是一个接口,有两个实现类,我们使用 RegexRegisteredService  ,该实现类支持RegisteredService的正则匹配。

    allowedAttributes 很重要,后面我们将用它来过滤返回给接入服务的attribute。
 

修改登录方法和根据业务系统返回不同数据

登录的方法是定义在 deployerConfigContext.xml  的

1<bean id="authenticationManager" 2 class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager"> 3 <constructor-arg> 4 <map> 5 <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" /> 6 <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> 7 </map> 8 </constructor-arg> 9 <property name="authenticationPolicy"> 10 <bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" /> 11 </property> 12</bean>

其中primaryAuthenticationHandler控制的是登录认证 ,primaryPrincipalResolver是返回的属性

primaryAuthenticationHandler 修改如下

1 <bean id="primaryAuthenticationHandler" 2 class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler" 3 p:dataSource-ref="dataSource" p:passwordEncoder-ref="MD5PasswordEncoder" 4 p:sql="select PWD from T_USER where USERACCOUNT = ?" /> 5 6 <bean id="MD5PasswordEncoder" 7 class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"> 8 <constructor-arg index="0"> 9 <value>MD5</value> 10 </constructor-arg> 11 </bean>

因为我们认证相对比较简单,这里使用QueryDatabaseAuthenticationHandler去处理登录时候的认证

主要是primaryPrincipalResolver的处理,这里是处理的认证成功后,返回业务系统的用户的数据,默认只返回了userId,我们需要返回更多的数据,这里自己定义一个类来处理

1 <bean id="primaryPrincipalResolver" 2 class="com.xxx.xxx.sso.MyPrincipalResolver" 3 p:casDao-ref="casDao" /> 4 5 6public class MyPrincipalResolver implements PrincipalResolver { 7 protected final Logger logger = LoggerFactory.getLogger(this.getClass()); 8 9 @NotNull 10 private CasDao casDao; 11 12 13 @Override 14 public Principal resolve(Credential credential) { 15 16 final MyUsernamePasswordCredentials usernamePasswordCredentials = (MyUsernamePasswordCredentials) credential; 17 String userStr = ""; 18 Map<String,Object> attr = new HashMap<String,Object>(); 19 20 try { 21 String username = usernamePasswordCredentials.getUsername(); 22 userStr = username; 23 User user = casDao.queryUser(username); 24 25 for(Role role : user.getRoles()){ 26 Map<String,Object> systemAttr = new HashMap<String,Object>(); 27 //TODO 设置要返回给接入服务的属性 28 attr.put(role.getSystemCode(), systemAttr); 29 } 30 31 return new SimplePrincipal(userStr, attr); 32 33 } catch (Exception e) { 34 logger.error("获取用户属性异常{}",e); 35 } 36 return null; 37 } 38 39 @Override 40 public boolean supports(Credential credential) { 41 return true; 42 } 43 44 public void setCasDao(CasDao casDao) { 45 this.casDao = casDao; 46 } 47 48}

    这里描述一下业务场景

        我们经常遇到如下需求,N个系统接入CAS;

        对于同一个用户,N个系统可能有不同的属性信息(比如针对每个系统用户的权限信息),每个系统之间,这类信息应该做到隔离。

       所以我们在用户登录后,构造一个Map, 使用接入系统的代码去做key,想想前面我们在构造registeredServices是,设置的

setAttributeReleasePolicy(new ReturnAllowedAttributeReleasePolicy(allowedAttributes));

cas会根据这个去过滤相关的属性。

    有人问 ,为什么要全取出来 ,而不是根据登录系统的情况,每次动态获取呢?

    可以测试一下,登录完A系统后,如果用户直接点击B系统,CAS是不会进入这个方法的。

    修改对应的protocol模板,返回属性,由于我们接入系统,使用的是 shiro cas那个包,支持的是2.0的协议,所以修改view/protocol/2.0/casServiceValidationSuccess.jsp

1<%@ page session="false" contentType="application/xml; charset=UTF-8" %> 2<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> 4<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'> 5 <cas:authenticationSuccess> 6 <cas:user>${fn:escapeXml(principal.id)}</cas:user> 7 <!-- 这段 --> 8 <c:if test="${fn:length(assertion.primaryAuthentication.principal.attributes) > 0}"> 9 <cas:attributes> 10 <c:forEach var="attr" items="${assertion.primaryAuthentication.principal.attributes}"> 11 <c:forEach var="systemAttr" items="${attr.value}"> 12 <cas:${fn:escapeXml(systemAttr.key)}>${fn:escapeXml(systemAttr.value)}</cas:${fn:escapeXml(systemAttr.key)}> 13 </c:forEach> 14 </c:forEach> 15 </cas:attributes> 16 </c:if> 17 <!-- 这段 end--> 18 <c:if test="${not empty pgtIou}"> 19 <cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket> 20 </c:if> 21 <c:if test="${fn:length(chainedAuthentications) > 0}"> 22 <cas:proxies> 23 <c:forEach var="proxy" items="${chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(chainedAuthentications)}" step="1"> 24 <cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy> 25 </c:forEach> 26 </cas:proxies> 27 </c:if> 28 </cas:authenticationSuccess> 29</cas:serviceResponse>
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )