CAS學習筆記(三)—— SERVER登錄后用戶信息的返回


一旦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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM