一旦CAS SERVER验证成功后,我们就会跳转到客户端中去。跳转到客户端去后,大家想一想,客户端总要获取用户信息吧,不然客户端是怎么知道登录的是哪个用户。那么客户端要怎么获取用户信息呢?

其实验证成功,跳转客户端这个过程中,CAS SERVER 会返回登录的相关信息给客户端,客户端只要进行获取,就能知道登录的具体是哪个用户了。不过CAS 默认只返回用户账号给客户端,那么怎么定义CAS SERVER返回的信息呢? 这就是本篇具体讲解的内容了,大家听我慢慢道来。

相关接口                                                               

在开始时,我们先了解下有关相关的几个接口

  • Credentials
  • Principal
  • IPersonAttributeDao
  • PrincipalResolver

Credentials                                                    

  Credentials (org.jasig.cas.authentication.Credentials)接口,我们在上一篇其实有使用过,我们当时有用过一个叫 UsernamePasswordCredential 的类,就是实现了Credentials接口。这个接口是用来定义我们登录页上输入的认证信息的,比如用户名、密码、验证码等,可以理解为用户认证的相关凭据。

Principal                                                     

  Principal (org.jasig.cas.authentication.principal.Principal) 接口,这个主要是用来保存用户认证后的用户信息,信息保存在一个Map中。

IPersonAttributeDao                                              

  IPersonAttributeDao (org.jasig.services.persondir.IPersonAttributeDao) 接口,这个是用来定义我们需要返回给客户端相关信息的接口,CAS SERVER 默认有提供许多实现,比如

  • LdapPersonAttributeDao :通过查询 LDAP 目录 ,来返回信息
  • SingleRowJdbcPersonAttributeDao : 通过JDBC SQL查询,来返回信息

等等,还有许多,大家可以参考源码中的实现,CAS SERVER 提供了各种功能的实现,有时候我们可以直接使用这个现成的就行了。

PrincipalResolver                                                 

  PrincipalResolver(org.jasig.cas.authentication.principal.PrincipalResolver) 接口,上面有说到 Credentials 是从登录页面上进行获取相关用户信息的。那么认证成功后,怎么把Credentials里面的信息转换到 Principal  中呢,这就是这个接口的作用了。由于认证本身是没有返回用户信息的,只是确定认证是通过还是没有通过。这时还要用到我们上面的IPersonAttributeDao 接口,在这接口中我们就可以定义我们需要返回的信息了。

这接口中有两个方法

  • resolve : 解析Credentials中的信息,返回 Principal 接口
  • supports : 判断Credentials 是否支持 Principal 协议。

ps: 在3.x版本中没有 PrincipalResolver接口,对应的是CredentialsToPrincipalResolver, PrincipalResolver这个是在4.0版本中加入的,大家要注意。

流程                                           

相关接口讲解后,大家应该对怎么返回信息有个大概的思路了。没错就是实现上面所说的 IPersonAttributeDao 、PrincipalResolver 接口 。下面根据代码讲解下具体的一个流程:

首先打开 deployerConfigContext.xml 文件,看下面的定义:

 <!--
| Resolves a principal from a credential using an attribute repository that is configured to resolve
| against a deployer-specific store (e.g. LDAP).
-->
<bean id="primaryPrincipalResolver"
class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" >
<property name="attributeRepository" ref="attributeRepository" />
</bean> <!--
Bean that defines the attributes that a service may return. This example uses the Stub/Mock version. A real implementation
may go against a database or LDAP server. The id should remain "attributeRepository" though.
+-->
<bean id="attributeRepository" class="org.jasig.services.persondir.support.StubPersonAttributeDao"
p:backingMap-ref="attrRepoBackingMap" /> <util:map id="attrRepoBackingMap">
<entry key="uid" value="uid" />
<entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
<entry key="groupMembership" value="groupMembership" />
</util:map>

//PersonDirectoryPrincipalResolver 部分源码

public final Principal resolve(final Credential credential) {
logger.debug("Attempting to resolve a principal...");
  
String principalId = extractPrincipalId(credential); //extractPrincipalId 方法从credential中抽取id //省略...
final IPersonAttributes personAttributes = this.attributeRepository.getPerson(principalId); //根据IPersonAttributeDao 中的getPerson 获取返回的属性
final Map<String, List<Object>> attributes; //最终返回 Principal
return new SimplePrincipal(principalId, convertedAttributes);
}

具体流程:

1.从上面的deployerConfigContext.xml 配置我们可以看到,CAS 默认配置了一个叫做 PersonDirectoryPrincipalResolver 的类,在 这个类的 resolve  方法中有调用 extractPrincipalId 这个方法,这个方法传入一个 Credentials 类型的参数,默认调用的是Credentials  的getId() 方法,CAS默认是返回用户的userName,即登录账号。不过getId()  这个方法的实现我们可以在上一章中指定的UsernamePasswordCredential 类中自定义,一般是定义成返回用户的userId或者其他唯一键,因为我们如果知道了用户的userId,那么就可以根据这个从数据库中查询中用户的一些具体信息了,进而就可以组成我们需要返回的信息。

2. 继续往下看源码,接着在 PersonDirectoryPrincipalResolver  中有注入一个 attributeRepository 属性,这个就是上面的IPersonAttributeDao 接口,然后在resolve方法中调用了 IPersonAttributeDao 接口 的getPerson方法,还传入了一个参数principalId,其实这个传入的参数就是我们上面 getId() 返回的值。

所以其实我们只要实现我们需要的 IPersonAttributeDao  就可以了。 下面给一个简单的IPersonAttributeDao  例子:

public class BlogStubPersonAttributeDao extends StubPersonAttributeDao {

    @Override
public IPersonAttributes getPerson(String uid) { Map<String, List<Object>> attributes = new HashMap<String, List<Object>>();
attributes.put("userid", Collections.singletonList((Object)uid));
attributes.put("cnblogUsername", Collections.singletonList((Object)"http://www.cnblogs.com/vhua"));
attributes.put("cnblogPassword", Collections.singletonList((Object)"123456"));
attributes.put("test", Collections.singletonList((Object)"test"));
return new AttributeNamedPersonImpl(attributes);
} }

这边传入的uid 默认是用户的登录名,我们这边没有做修改,直接用默认的。

这边是只是测试用,所以就直接写死了,实际开发肯定是需要在数据库或者LDAP中进行查询后,然后组装成需要的信息 。

然后在 deployerConfigContext.xml 中修改

<bean id="primaryPrincipalResolver"
class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" >
<property name="attributeRepository" ref="attributeRepository" />
</bean>
<!-- 修改前 -->
<bean id="attributeRepository" class="org.jasig.services.persondir.support.StubPersonAttributeDao"
p:backingMap-ref="attrRepoBackingMap" /> <util:map id="attrRepoBackingMap">
<entry key="uid" value="uid" />
<entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
<entry key="groupMembership" value="groupMembership" />
</util:map>
<!-- 修改前 end-->

<!--修改后-->
<bean id="attributeRepository" class="org.jasig.services.persondir.support.BlogStubPersonAttributeDao" />
<!--修改后 end-->

3. 修改完成后,我们还需要在 casServiceValidationSuccess.jspcas-server-webapp\src\main\webapp\WEB-INF\view\jsp\protocol\2.0\casServiceValidationSuccess.jsp)

添加一段代码(下面红色部分):

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>${fn:escapeXml(assertion.primaryAuthentication.principal.id)}</cas:user>

    <!-- 这段 -- >
<c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}">
<cas:attributes>
<c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}">
<cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>
</c:forEach>
</cas:attributes>
</c:if>
<!-- 这段 end-- > <c:if test="${not empty pgtIou}">
<cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
</c:if>
<c:if test="${fn:length(assertion.chainedAuthentications) > 1}">
<cas:proxies>
<c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1">
<cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>
</c:forEach>
</cas:proxies>
</c:if>
</cas:authenticationSuccess>
</cas:serviceResponse>

4. 接下来 在客户端设置信息的接收,我们直接在index.jsp中测试一下:

Java中可以通过下面的方式获取

AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();

Map attributes = principal.getAttributes();

String xxx=attributes .get("xxx");

...

<!DOCTYPE html">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>返回值测试</title>
</head>
<body> <%
request.setCharacterEncoding("UTF-8");
AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
Map attributes = principal.getAttributes();
String userid=(String)attributes.get("userid");
String cnblogUsername = (String)attributes.get("cnblogUsername");
String cnblogPassword = (String)attributes.get("cnblogPassword");
String test=(String)attributes.get("test"); %>
<div>飞奔的蜗牛博客:返回值演示</div>
<ul>
<li>userid:<%= userid%></li>
<li>username:<%= cnblogUsername%></li>
<li>password:<%= cnblogPassword%></li>
<li>test:<%= test%></li>
</ul>
</body>
</html>

效果                                           

好了,我们登录运行看看结果。

大家看到没,已经获取成功了,在CAS SERVER那边设置的信息,我们正常获取到了 。大家可以根据业务的需要,返回相关的信息。然后在客户端进行操作。

转自:http://www.cnblogs.com/vhua/p/cas_4.html

CAS学习笔记(三)—— SERVER登录后用户信息的返回的更多相关文章

  1. 【SSO单点系列】(4):CAS4.0 SERVER登录后用户信息的返回

    接着上一篇,在上一篇中我们描述了怎么在CAS SERVER登录页上添加验证码,并进行登录.一旦CAS SERVER验证成功后,我们就会跳转到客户端中去.跳转到客户端去后,大家想一想,客户端总要获取用户 ...

  2. CAS学习笔记三:SpringBoot自动配置与手动配置过滤器方式集成CAS客户端

    本文目标 基于SpringBoot + Maven 分别使用自动配置与手动配置过滤器方式集成CAS客户端. 需要提前搭建 CAS 服务端,参考 https://www.cnblogs.com/hell ...

  3. CAS学习笔记五:SpringBoot自动/手动配置方式集成CAS单点登出

    本文目标 基于SpringBoot + Maven 分别使用自动配置与手动配置过滤器方式实现CAS客户端登出及单点登出. 本文基于<CAS学习笔记三:SpringBoot自动/手动配置方式集成C ...

  4. Spring MVC 学习笔记10 —— 实现简单的用户管理(4.3)用户登录显示全局异常信息

    </pre>Spring MVC 学习笔记10 -- 实现简单的用户管理(4.3)用户登录--显示全局异常信息<p></p><p></p>& ...

  5. Spring MVC 学习笔记9 —— 实现简单的用户管理(4)用户登录显示局部异常信息

    Spring MVC 学习笔记9 -- 实现简单的用户管理(4.2)用户登录--显示局部异常信息 第二部分:显示局部异常信息,而不是500错误页 1. 写一个方法,把UserException传进来. ...

  6. Spring MVC 学习笔记8 —— 实现简单的用户管理(4)用户登录

    Spring MVC 学习笔记8 -- 实现简单的用户管理(4)用户登录 增删改查,login 1. login.jsp,写在外面,及跟WEB-INF同一级目录,如:ls Webcontent; &g ...

  7. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  8. kvm虚拟化学习笔记(三)之windows kvm虚拟机安装

    KVM虚拟化学习笔记系列文章列表----------------------------------------kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51 ...

  9. CAS学习笔记(一)

    近期做单点登录,看了一些CAS资料,做下总结 一.cas简介 全名:Central Authentication Service 特点: 1.开源的.多协议的 SSO 解决方案: Protocols  ...

随机推荐

  1. COM简单应用示例

    使用com技术开发模式进行的示例. com技术关键部分源码:主要将所有接口都写入到这个文件中 testinterface.h #ifndef TESTINTERFACE_H #define TESTI ...

  2. Android Studio中JNI -- 2 -- 编写c文件

    继上一篇,我们在native接口中编写了2个方法 生成的相应.h文件 这时,需要我们自己去完善.c文件 /* DO NOT EDIT THIS FILE - it is machine generat ...

  3. 基于管道通知的百万并发长连接server模型

    0.前言 最近突然想了解怎样设计一个支持百万连接的后台server架构. 要设计一个支持百万连接的后台server,我们首先要知道会有哪些因素限制后台server的高并发连接,这里想到的因素有以下几点 ...

  4. 【原创】CMD常用命令:解决实际问题

    1.查找某一目录下后缀名文某某的所有文件. 命令格式:dir *.mp3 /a -d/b/s >C:\Users\leemo\Desktop\total.txt MP3为文件后缀名.>是命 ...

  5. win8 + ubuntu14.04 安装步骤

    一.首先,从硬盘上划分一个空闲分区(推荐最少20G,每个人也可以按照自己的需要自行设定).记住各个分区的容量,方便安装时辨认.并从Ubuntu官方网站上下载Ubuntu 14.04 LTS 光盘镜像. ...

  6. Python 学习笔记(3) - 控制流、函数

    控制流语句if.while.for.break.continue以上从最终作用效果来讲,同学过的其他语言没有什么不同.需要注意的只是语法,而Python 在语法上是如此让人赞叹和喜欢啊. 控制流语句的 ...

  7. struts中如何将前台的值能在action中获取到

    如何获取值----三种方式(属性驱动,对象驱动,模型驱动)  A:属性驱动 必须生成get,set方法  B:对象驱动 给对象也必须生成get,set方法  c模型驱动 模型驱动需要action去实现 ...

  8. ALTER TABLE 语句与 FOREIGN KEY 约束"FK_SCHEDULE_REFERENCE_POSTCONF"冲突。

    主要原因是因为两个表中有数据不匹配,只要把不匹配的数据删掉就行了.

  9. iPhone手机VPN设置

    如果iPhone,iPad游戏或软件服务器在国外不能用,就需要设置VPN了. 如果是为了解除公司上网策略限制,或者为了上Google,Facebook,都可以通过设置VPN实现. 要使用VPN需要到V ...

  10. 小测几种python web server的性能

    http://blog.csdn.net/raptor/article/details/8038476 因为换了nginx就不再使用mod_wsgi来跑web.py应用了,现在用的是gevent-ws ...