zoukankan      html  css  js  c++  java
  • [原]基于CAS实现单点登录(SSO):登录成功后,cas client如何返回更多用户信息

    cas server登录成功后,默认只能从casclient得到用户名。但程序中也可能遇到需要得到更多如姓名,手机号,email等更多用户信息的情况。

    cas client拿到用户名后再到数据库中查询,的确可以得到关于该用户的更多信息。

    但是如果用户登录成功后,直接从cas server返回给casclient用户的详细信息,这也是一个不错的做法。这个好处,尤其是在分布式中得以彰显,cas server可以把用户信息传递给各个应用系统,如果是上面那种做法,那么各个系统得到用户名后,都得去数据库中查询一遍,无疑是一件重复性工作。

     

    文章中 CAS 基础环境:

    cas-server-3.5.2    

    cas-client-3.2.1

     一、首先需要配置属性attributeRepository

    首先,你需要到WEB-INF目录找到 deployerConfigContext.xml文件,同时配置attributeRepository 如下: 

    <bean  class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao"id="attributeRepository">
            <constructor-argindex="0" ref="casDataSource"/>
            <constructor-argindex="1" value="select * from userinfo where {0}"/>
            <propertyname="queryAttributeMapping">
                <map>
                    <entrykey="username" value="loginname"/>  // 这里的key需写username和登录页面一致,value对应数据库用户名字段
                </map>
            </property>
            <propertyname="resultAttributeMapping">
                <map>
    // <!--key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值-->  
                    <entrykey="id" value="id"/>
                    <entrykey="mobile" value="mobile"/>
                    <entrykey="email" value="email"/>
                </map>
            </property>
        </bean>

    其中:

    切记:查询出来的字段名中间不能使用 _ (下划线),否则获取不到数据,如 cell_phone 需要 设置别名为 cellPhone.

    queryAttributeMapping是组装sql用的查询条件属性,上述配置后,结合封装成查询sql就是 select *from userinfo where loginname=#username#

    resultAttributeMapping是sql执行完毕后返回的结构属性, key对应数据库字段,value对应客户端获取参数。

    如果要组装多个查询条件,需要加上下面这个,默认为AND

    <property name="queryType">

    <value>OR</value>

          </property>  

     

    二、配置用户认证凭据转化的解析器

    也是在 deployerConfigContext.xml 中,找到credentialsToPrincipalResolvers,为UsernamePasswordCredentialsToPrincipalResolver 注入 attributeRepository,那么attributeRepository 就会被触发并通过此类进行解析,红色为新添部分。

    <propertyname="credentialsToPrincipalResolvers">
                <list>        
                    <beanclass="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver">
                        <property name="attributeRepository"ref="attributeRepository"/>
                    </bean>
                    <beanclass="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver"/>
                </list>
     </property>

     三、配置InMemoryServiceRegistryDaoImpl属性 registeredServices

    修改 deployerConfigContext.xml 中的 org.jasig.cas.services.InMemoryServiceRegistryDaoImpl的 属性 registeredServices。修改 registeredServices  allowedAttributes属性值,将需要在客户端显示的列值加上。

    <bean  id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl">
               <property name="registeredServices">
                   <list>
                       <beanclass="org.jasig.cas.services.RegexRegisteredService">
                           <property name="id"value="0" />
                           <property name="name"value="HTTP and IMAP" />
                           <property name="description"value="Allows HTTP(S) and IMAP(S) protocols" />
                           <property name="serviceId"value="^(https?|imaps?)://.*" />
                           <propertyname="evaluationOrder" value="10000001" />
                           <propertyname="allowedAttributes"> // 客户端需要使用的对象的属性名称
                                   <list>
                                          <value>uid</value>
                                          <value>email</value>
                                          <value>mobile</value>
                                          <value>birth</value>
                                          <value>isMarry</value>
                                          <value>userno</value>
                                          <value>login_account</value>
                                   </list>
                           </property>
                       </bean>

    【提示】网上说此bean中的ignoreAttributes属性默认是不添加用户信息,查看了 CAS 3.5.2版本的 AbstractRegisteredService 源码后,发现其默认值就是false,即:添加属性后,客户端就可见了

     

    四、配置与客户端交互的xml信息

    修改WEB-INF/view/jsp/protocol/2.0/casServiceValidationSuccess.jsp。在server验证成功后,这个页面负责生成与客户端交互的xml信息,在默认的casServiceValidationSuccess.jsp中,只包括用户名,并不提供其他的属性信息,因此需要对页面进行扩展,如下,红色为新添加部分 

    <cas:serviceResponsexmlns:cas='http://www.yale.edu/tp/cas'>
      <cas:authenticationSuccess>
    <cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)}</cas:user>
       <c:iftest="${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>
    <c:if test="${not empty pgtIou}">
      <cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
    </c:if>
    <c:iftest="${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>

     

    通过完成上面四个步骤的配置后,server端的工作就完成了,那么如何在客户端获取这些信息呢?下面进行说明:

     

    客户端获取用户信息

    cas client获取用户信息:

    AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();
    Map attributes = principal.getAttributes();
    String email=attributes .get("email");

    shiro集成后获取用户信息:

    和shiro集成后,因为cas client将casFilter交给了shiroFilter,所以在通过shiro对象时可以用户信息的:

    Subject subject = SecurityUtils.getSubject();
     
    List list = subject.getPrincipals().asList();
    String name = (String) list.get(0);
    Map<String, Object> info = (Map<String, Object>)list.get(1);
     
    String age = info.get("age").toString();


    作者:tcl_6666 发表于2014-3-27 11:10:26 原文链接
    阅读:984 评论:11 查看评论
  • 相关阅读:
    Oracle序列更新
    ssh服务器终端乱码
    iTerm2常用的快捷键
    原来 Set 集合也可以排序
    Java 单例
    java后台技术
    网易考拉规则引擎平台架构设计与实践
    HBase最佳实践(好文推荐)
    如何通俗的解释云
    写的不错的一篇云数据库的文章
  • 原文地址:https://www.cnblogs.com/mxcy/p/3982118.html
Copyright © 2011-2022 走看看