前言
本文主要解决的技术问题:
- CAS登录页面怎样增加除用户名,密码以外的参数,例如要增加用户身份?
- CAS server认证成功后,怎么返回对应身份的用户信息?
怎么解决上述问题呢?
思路:
- 弄明白Cas的基本概念
- 弄明白Cas是怎么使用的
- 弄明白Cas-server代码实现流程
- 弄明白问题对应代码切入点
接下来是具体实践过程:
一、CAS是什么
直接百度:CAS(中央认证服务)
其中对协议过程图的分析,可以清楚CAS 通信原理。
二、CAS是怎么使用
网上找到实战springboot+CAS单点登录系统课程,介绍了cas-server 与 cas-client的搭建,掌握cas基本使用。不足之处,课程对cas-server环境搭建直接使用的war包tomcat部署,对于cas-server后台源码实现流程没有做详细分析。
课程地址:
war包下载地址:
https://repo1.maven.org/maven2/org/apereo/cas/cas-server-webapp-tomcat/
三、Cas实现流程
了解Cas使用后,发现cas-server通过不同的参数配置策略,实现单点登录,对于各个配置文件的介绍:Cas Server配置文件。
博文说“login-webflow.xml:登录使用到的Spring Web Flow配置文件”,引出了Spring Web Flow这种技术,Spring Web Flow在cas 是怎么使用的,可阅读下面博文:
Spring Web Flow —— 基础 - 011_zou8944的博客-CSDN博客_web-flow
CAS学习笔记(二)—— cas server端的login-webflow详细流程_qq_30220585的博客-CSDN博客
弄清楚login-webflow 就会了解cas的登录流程。第二篇博文中提到了casLoginView.jsp这个文件,通过阅读cas登陆页面修改服务器端 发现casLoginView其实就是登录页,是解决问题的切入点之一,casLoginView.jsp文件中大量使用了<form:xxx> 标签,说明页面的实现采用了springmvc form技术,实现原理见博文 SpringMVC - Form标签
Cas Server配置文件博文中:“deployerConfigContext.xml:该文件是专为Cas Server部署人员抽取出来的一个文件,其中的内容通常都是Cas Server部署人员需要进行更改的内容”。在cas 实践课程中也提及到,通过配置deployerConfigContext.xml 文件可以实现数据源认证,那么认证过程中,是不是可以添加更多的查询参数返回所需结果,这里也是问题切入点。deployerConfigContext 使用详解:
至此就会对cas实现流程有一个相对深刻的认识,接下来就是问题的解决。
四、问题解决
在问题解决之前,先看一下这篇博文:
文章提供了UsernamePasswordCredential扩展字段,校验字段的方法。
现在开始问题的解决:
登录页面怎样增加除用户名,密码以外的参数?
- 修改casLoginView.jsp 增加 swrysfSelect下拉框,及 swrysf 隐藏域
<div class="kema_shuru1" style=" position: relative;">
<div class="kema_shurmingc"></div>
<spring:message code="screen.welcome.label.netid.accesskey"
var="userNameAccessKey" />
<span style=" position: absolute; top:5px; left:10px;"><img src="${basepath}static/images/login/user_icon.png" /></span>
<form:input id="username" tabindex="1"
accesskey="${userNameAccessKey}" type="text" cssClass=""
class="kema_inpyonghum" value="" placeholder="请输入您的用户名"
path="username" autocomplete="false" htmlEscape="true" />
</div>
<div class="clearfix"></div>
<div class="kema_shuru1" style=" position: relative; margin-top:0px; margin-bottom: 0px;">
<div class="kema_shurmingc" style="height: 40px;"></div>
<span style=" position: absolute; top:5px; left:10px;"><img src="${basepath}static/images/login/password_icon.png" /></span>
<form:password id="password" type="password" cssClass=""
class="kema_inpyonghum" value="" placeholder="请输入您的密码"
tabindex="2" path="password" accesskey="${passwordAccessKey}"
htmlEscape="true" autocomplete="off" />
</div>
<div class="clearfix"></div>
<div class="kema_shuru1" style=" position: relative;margin-top:20px;margin-bottom:-20px;">
<div class="kema_shurmingc"></div>
<span style=" position: absolute; top:5px; left:10px;"><img src="${basepath}static/images/login/user_icon.png" /></span>
<select id="swrysfSelect" class="kema_inpyonghum">
</select>
<form:input path="swrysf" id="swrysf" name="swrysf" type="hidden" ></form:input>
</div>
其中:swrysfSelect 是一个下拉框的数据是username失去焦点后,异步数据查询动态创建的。
swrysf 在swrysfSelect值改变时,会绑定对应选中值。
- UsernamePasswordCredential扩展,增加字段
参考cas服务器登录页面添加验证码,新建类UsernamePasswordAndSwrySfCredentials,添加一个swrysf字段:
/**
* 用户密码身份
*/
public class UsernamePasswordAndSwrySfCredentials extends UsernamePasswordCredentials{
private static final long serialVersionUID = 1L;
@NotNull
private String swrysf;
public final String getSwrysf() {
return swrysf;
}
public final void setSwrysf(String swrysf) {
this.swrysf = swrysf;
}
}
- login-webflow credentials变量修改为UsernamePasswordAndSwrySfCredentials
<!--<var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />-->
<var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordAndSwrySfCredentials" />
<on-start>
<evaluate expression="initialFlowSetupAction" />
</on-start>
...... 省略部分代码
<view-state id="viewLoginForm" view="casLoginView" model="credentials">
<binder>
<binding property="username" />
<binding property="password" />
<binding property="swrysf" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credentials'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="submit">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
</transition>
</view-state>
登录提交时 username password swrysf 绑定到 UsernamePasswordAndSwrySfCredentials对应字段中。
接下来是处理返回对应身份的用户信息信息:
在deployerConfigContext.xml 配置
<bean class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao" id="attributeRepository">
<constructor-arg index="0" ref="dataSource"/>
<constructor-arg index="1" value="select * from table where {0} "/>
<property name="queryAttributeMapping">
<map>
<entry key="username" value="dlzh_dm"/>
<entry key="swrysf" value="swrysf_dm"/>
</map>
</property>
<property name="resultAttributeMapping">
<map>
<entry key="返回字段1" value="返回字段1"/>
<entry key="返回字段2" value="返回字段2"/>
<entry key="返回字段3" value="返回字段3"/>
<entry key="返回字段4" value="返回字段4"/>
</map>
</property>
</bean>
修改AbstractPersonDirectoryCredentialsToPrincipalResolver.java
//修改方式getPerson 方法 由调用 principalId(username) 的方式 改为调用 Map 的方式,Map 包括 username及swrysf 参数
//final IPersonAttributes personAttributes = this.attributeRepository.getPerson(principalId);
Map<String,Object> params = new HashMap<String, Object>();
UsernamePasswordAndSwrySfCredentials credentialsWithSwrySf = (UsernamePasswordAndSwrySfCredentials)credentials;
params.put(USERNAME,credentialsWithSwrySf.getUsername());
params.put(SWRYSF,credentialsWithSwrySf.getSwrysf());
Set<IPersonAttributes> people = this.attributeRepository.getPeople(params);
Iterator<IPersonAttributes> iterator = people.iterator();
final IPersonAttributes personAttributes = iterator.next();
final Map<String, List<Object>> attributes;
这样 select * from table where {0} sql 会替换成 select * from table where dlzh_dm = ? and swrysf_dm = ? 同时绑定params 参数值,就可以返回具体身份下的人员信息。
问题解决