CAS SSO 4.0.x 返回更多用户信息

从cas server登录成功后,默认只能从cas server得到用户名。但程序中也可能遇到需要得到更多如姓名,手机号,email等更多用户信息的情况。cas client拿到用户名后再到数据库中查询,的确可以得到关于该用户的更多信息。但是如果用户登录成功后,直接从cas server返回给cas client用户的详细信息,这也是一个不错的做法。这个好处,尤其是在分布式中得以彰显,cas server可以把用户信息传递给各个应用系统,如果是上面那种做法,那么各个系统得到用户名后,都得去数据库中查询一遍,无疑是一件重复性工作。

1、首先需要配置属性attributeRepository

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

<bean  class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao" id="attributeRepository">  
    <constructor-arg index="0" ref="dataSource"/>  
    <constructor-arg index="1" value="select * from t_user where {0}"/>  
    <property name="queryAttributeMapping">  
        <map>  
            <!--这里的key需写username和登录页面一致,value对应数据库用户名字段-->  
            <entry key="username" value="loginname"/>  
        </map>  
    </property>  
    <property name="resultAttributeMapping">  
        <map>  
            <!--key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值-->  
            <entry key="suid" value="suid"/>  
        </map>  
    </property>  
    <!--    
    <property name="queryType">  
        <value>OR</value>  
    </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>   

2、修改serviceRegistryDao

deployerConfigContext.xml中的 beans中id为serviceRegistryDao的属性 registeredServicesList。在 registeredServicesList中添加allowedAttributes属性的值。列出的每个值,在客户端就可以访问了。

<util:list id="registeredServicesList">  
    <bean class="org.jasig.cas.services.RegexRegisteredService"  
          p:id="0" p:name="HTTP and IMAP" p:description="Allows HTTP(S) and IMAP(S) protocols"  
          p:serviceId="^(http?|https?|imaps?)://.*" p:evaluationOrder="10000001">  
          <!-- 添加该属性allowedAttributes -->  
          <property name="allowedAttributes">  
              <list>  
                  <value>suid</value>  
              </list>  
          </property>  
    </bean>  
</util:list> 

此步骤非常重要,可以看看org.jasig.cas.services.RegexRegisteredService的源码,其中的allowedAttributes是关键。

3、修改casServiceValidationSuccess.jsp

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

<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="${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: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、CAS Client获取用户信息

AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
Map attributes = principal.getAttributes();
String email = attributes.get(“suid”);

5、自定义SQL查询用户信息

在步骤一,使用SQL比较单一,这样我就发现了类org.jasig.services.persondir.support.jdbc.NamedParameterJdbcPersonAttributeDao这个类中有DataSource和sql.但是我发现使用这个类我无法使用自定义查询SQL因为不能随便自己来传入参数,所以可以自己写类实现类org.jasig.services.persondir.support.AbstractDefaultAttributePersonAttributeDao。具体代码如下:

package org.jasig.cas.myself.persondir.support;  

import java.sql.ResultSet;  
import java.sql.SQLException;  
import java.util.Collections;  
import java.util.HashMap;  
import java.util.List;  
import java.util.Map;  
import java.util.Set;  

import javax.sql.DataSource;  

import org.jasig.services.persondir.IPersonAttributes;  
import org.jasig.services.persondir.support.AbstractDefaultAttributePersonAttributeDao;  
import org.jasig.services.persondir.support.CaseInsensitiveNamedPersonImpl;  
import org.jasig.services.persondir.support.IUsernameAttributeProvider;  
import org.springframework.beans.factory.InitializingBean;  
import org.springframework.beans.factory.annotation.Required;  
import org.springframework.jdbc.core.JdbcTemplate;  
import org.springframework.jdbc.core.RowMapper;  

import com.google.common.collect.Lists;  

public class MyNamedParameterJdbcPersonAttributeDao extends AbstractDefaultAttributePersonAttributeDao implements InitializingBean {  

    private JdbcTemplate jdbcTemplate;  

    private DataSource dataSource;  
    private String sql;  
    private IUsernameAttributeProvider usernameAttributeProvider;  
    private Set<String> availableQueryAttributes = null;  // default  
    private Set<String> userAttributeNames = null;  // default  

    @Required  
    public void setDataSource(DataSource dataSource) {  
        this.dataSource = dataSource;  
    }  

    @Required  
    public void setSql(String sql) {  
        this.sql = sql;  
    }  

    @Required  
    public void setUsernameAttributeProvider(IUsernameAttributeProvider usernameAttributeProvider) {  
        this.usernameAttributeProvider = usernameAttributeProvider;  
    }  

    public void setAvailableQueryAttributes(Set<String> availableQueryAttributes) {  
        this.availableQueryAttributes = Collections.unmodifiableSet(availableQueryAttributes);  
    }  

    @Required  
    public void setUserAttributeNames(Set<String> userAttributeNames) {  
        this.userAttributeNames = Collections.unmodifiableSet(userAttributeNames);  
    }  

    @Override  
    public void afterPropertiesSet() throws Exception {  
        jdbcTemplate = new JdbcTemplate(dataSource);  
    }  

    @Override  
    public Set<String> getAvailableQueryAttributes() {  
        return availableQueryAttributes;  
    }  

    @Override  
    public Set<IPersonAttributes> getPeopleWithMultivaluedAttributes(Map<String, List<Object>> queryParameters) {  
        String username = usernameAttributeProvider.getUsernameFromQuery(queryParameters);  
        Map<String,List<Object>> mapOfLists = new HashMap<String,List<Object>>();  
        Object suid = jdbcTemplate.queryForObject(sql, new RowMapper<Object>() {  

            @Override  
            public Object mapRow(ResultSet paramResultSet, int paramInt) throws SQLException {  
                // TODO Auto-generated method stub  
                return paramResultSet.getObject("SUID");  
            }}, new Object[]{username,username,username});  
        if(null != suid){  
            mapOfLists.put("suid", Lists.newArrayList(suid));  
        }  
        return getResults(username, mapOfLists);  
    }  

    @Override  
    public Set<String> getPossibleUserAttributeNames() {  
        return userAttributeNames;  
    }  

    public Set<IPersonAttributes> getResults(String username, Map<String, List<Object>> attributes) {  
        IPersonAttributes person = new CaseInsensitiveNamedPersonImpl(username, attributes);  
        return Collections.singleton(person);  
    }  

}  

然后在deployerConfigContext.xml文件做如下修改:

<bean id="attributeRepository" class="org.jasig.cas.myself.persondir.support.MyNamedParameterJdbcPersonAttributeDao">   
    <property name="dataSource" ref="dataSource"/>  
    <property name="sql" value="select suid from login where NAME = ? or CELLPHONE = ? or EMAIL = ?" />  
    <property name="usernameAttributeProvider" ref="usernameAttributeProvider"/>  
    <property name="userAttributeNames">  
        <value>suid</value>  
    </property>  
</bean>  

<bean id="usernameAttributeProvider" class="org.jasig.services.persondir.support.SimpleUsernameAttributeProvider" />  

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
    <property name="driverClass" value="${cust.center.jdbc.driverClassName}" />  
    <property name="jdbcUrl" value="${cust.center.jdbc.url}" />  
    <property name="user" value="${cust.center.jdbc.username}" />  
    <property name="password" value="${cust.center.jdbc.password}" />  
    <property name="preferredTestQuery" value="SELECT 1"/>  
    <property name="idleConnectionTestPeriod" value="18000"/>  
    <property name="testConnectionOnCheckout" value="true"/>  
</bean>  

这样自定义查询方式就完成了,也可以返回更多用户信息。当然我这是只返回一个多余信息。如果你需要返回多个,可以做相应的修改哈。
参考地址:基于CAS实现单点登录(SSO):登录成功后,cas client如何返回更多用户信息

©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页