CAS返回對象的更多屬性Assertion.getPrincipal().getAttributes()
服務器,在返回給客戶端用戶信息時,默認只返回用戶名(我們已經修改成ID).但有時我們需要更多的屬性信息,如用戶名。
則應做如下修改:
用戶登錄成功以后,CAS使用一個credentialsToPrincipalResolvers將credentials轉成Principal對象,此對象只有一個實現類如下.
SimplePrincipal的構造方法接收兩個參數,一個是用戶的id,一個為用戶的其他屬性。用戶的ID默認為用戶登錄時使用的用戶名,前面第4點已經講過如何將用戶的name換成用戶的id返回給客戶端。為了給客戶端返回更多的屬性,我們必須要給Principal的構造方法傳遞第二個參數,它是一個Map<String,Object>類型。
具體代碼如下:
package cn.itcast.pubs;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.jasig.cas.authentication.principal.Credentials;
import org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver;
import org.jasig.cas.authentication.principal.Principal;
import org.jasig.cas.authentication.principal.SimplePrincipal;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.springframework.jdbc.core.JdbcTemplate;
public class MyCredentialsToPrincipalResolver implements CredentialsToPrincipalResolver {
private DataSource dataSource;//查詢數據庫用
@Override
public Principal resolvePrincipal(Credentials credentials) {
System.err.println("將憑據轉換成被代理人:"+credentials);
UsernamePasswordCredentials up = //強制類型轉換
(UsernamePasswordCredentials) credentials;
String name = up.getUsername();
String pwd = up.getPassword();
String sql = "select id from users2 where u2_name=? and u2_pwd=?"; //查詢id
String id = null;
try{
id=new JdbcTemplate(getDataSource()).queryForObject(sql, String.class, name,pwd);
if(id!=null){
//封裝其他信息
Map<String,Object> attrs = new HashMap<String,Object>();
attrs.put("username",name);
attrs.put("pwd",pwd);
Principal p = new SimplePrincipal(id,attrs);//封裝成包含id的Principal對象
System.err.println("生成的屬性值是::"+attrs);
return p;
}
}catch(Exception e){
e.printStackTrace();
}
return null;
}
@Override
public boolean supports(Credentials credentials) {
boolean boo = //判斷是否是用戶和密碼憑據
UsernamePasswordCredentials.class.isAssignableFrom(credentials.getClass());
return boo;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}
但,它并不會馬上顯示到客戶端,如果要顯示到客戶端,因為服務器驗證成功以后,是通過xml形式將結果傳遞給客戶端的,xml的生成由casServiceValidationSuccess.jsp文件負責。它的具體構造應該是以下形式:
<cas:serviceResponse
xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>U001</cas:user>
<cas:attributes>
<cas:pwd>1234</cas:pwd>
<cas:username>Jack</cas:username>
</cas:attributes>
</cas:authenticationSuccess>
</cas:serviceResponse>
在上面的代碼中,cas:attributes元素是筆者添加的,客戶端的的Filter在接收到上述的XML以后,會將css:attributes中的屬性解析出來,放到AttirubtePrincipal的attributes屬性中去(或是放到Asseration的attributes中去,兩個只會放一個)。
所以,組成上面的<cas :attributes>元素中的內容,就成了如何傳遞更多屬性的關鍵,在修改了MyCredentialsToPrincipalResolver的代碼以后,然后還必須要修改casServiceValidationSuccess.jsp的代碼如下:
<%@ page session="false" contentType="text/xml; charset=UTF-8"%><%@ taglib
prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><%@ taglib
uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%><cas:serviceResponse
xmlns: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: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:attributes>
<c:forEach
items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}"
var="attr">
<cas:${attr.key}>${attr.value}</cas:${attr.key}>
</c:forEach>
</cas:attributes>
</cas:authenticationSuccess>
</cas:serviceResponse>
然后修改deployerConfigContext.xml文件,將最后一個配置項:serviceRegistryDao中的所有屬性全部刪除或是注銷。
這個bean中的RegisteredServiceImpl的ignoreAttributes屬性將決定是否添加attributes屬性內容,默認為false:不添加,只有去掉這個配置,
cas server才會將獲取的用戶的附加屬性添加到認證用的Principal的attributes中去。
然后即可以在頁面上通過以下方式獲取用戶的其他屬性:
<%
Assertion assertion = AssertionHolder.getAssertion();
AttributePrincipal ap = assertion.getPrincipal(); //獲取AttributePrincipal對象,這是客戶端對象
String name = ap.getName();
Map<String,Object> att = ap.getAttributes(); //獲取屬性值,為一個Map類型。
out.print("<br/>"+name);
out.print("<br/>"+att);
%>