15

我正在使用带有 JDBC 身份验证处理程序的 CAS,并且想知道是否有可能在成功身份验证后获取主体对象的其他属性(例如名字、姓氏)而不仅仅是来自 CAS 的用户名?

4

5 回答 5

11

casServiceValidationSuccess.jsp中,我添加如下:

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

在 deployerConfigContent.xml 中,我添加如下:

<bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" >

    **<property name="attributeRepository">
     <ref bean="attributeRepository" />
    </property>**

</bean>

<bean id="attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">

    <constructor-arg index="0" ref="dataSource"/>
    <constructor-arg index="1" value="select * from bbs_members where {0}" />
    <property name="queryAttributeMapping">
       <map>
          <entry key="username" value="username" />
       </map>
    </property>

    <property name="resultAttributeMapping">
        <map>
            <entry key="uid" value="uid"/>
            <entry key="email" value="email"/>
            <entry key="password" value="password"/>
        </map>
    </property>
</bean>

有用。
我在调试过程中遇到了这个问题,如果你更改了这个JSP或XML文件,请关闭浏览器,否则更改将不起作用。当心。

于 2012-05-15T02:59:23.817 回答
3

要从数据库中获取任何用户属性,我执行了以下操作:使用PersonDirectoryPrincipalResolver

在 deployerConfigContext.xml 中:

<bean id="primaryPrincipalResolver"
      class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" >
    <property name="attributeRepository" ref="singleRowJdbcPersonMultiplyAttributeDao" />
</bean>

而不是使用标准SingleRowJdbcPersonAttributeDao类创建您自己的实现,它不仅从查询结果返回一行,而且从所有返回的行中返回聚合数据:

复制所有代码SingleRowJdbcPersonAttributeDao并仅更改一种方法parseAttributeMapFromResults。你会有类似的东西:

public class SingleRowJdbcPersonMultiplyAttributeDao extends AbstractJdbcPersonAttributeDao<Map<String, Object>> {
    ...

    @Override
    protected List<IPersonAttributes> parseAttributeMapFromResults(final List<Map<String, Object>> queryResults, final String queryUserName) {
        final List<IPersonAttributes> peopleAttributes = new ArrayList<IPersonAttributes>(queryResults.size());
        Map<String, List<Object>> attributes = new HashMap<String, List<Object>>();

        for (final Map<String, Object> queryResult : queryResults) {

            for (final Map.Entry<String, Object> seedEntry : queryResult.entrySet()) {
                final String seedName = seedEntry.getKey();
                final Object seedValue = seedEntry.getValue();

                if (attributes.get(seedName) != null && !attributes.get(seedName).get(0).equals(seedValue)) {
                    attributes.get(seedName).add(seedValue);
                } else {
                    List<Object> list = new ArrayList<Object>();
                    list.add(seedValue);
                    attributes.put(seedName, list);
                }

            }
        }

        final IPersonAttributes person;
        final String userNameAttribute = this.getConfiguredUserNameAttribute();
        if (this.isUserNameAttributeConfigured() && attributes.containsKey(userNameAttribute)) {
            // Option #1:  An attribute is named explicitly in the config,
            // and that attribute is present in the results from LDAP;  use it
            person = new CaseInsensitiveAttributeNamedPersonImpl(userNameAttribute, attributes);
        } else if (queryUserName != null) {
            // Option #2:  Use the userName attribute provided in the query
            // parameters.  (NB:  I'm not entirely sure this choice is
            // preferable to Option #3.  Keeping it because it most closely
            // matches the legacy behavior there the new option -- Option #1
            // -- doesn't apply.  ~drewwills)
            person = new CaseInsensitiveNamedPersonImpl(queryUserName, attributes);
        } else {
            // Option #3:  Create the IPersonAttributes doing a best-guess
            // at a userName attribute
            person = new CaseInsensitiveAttributeNamedPersonImpl(userNameAttribute, attributes);
        }

        peopleAttributes.add(person);
        return peopleAttributes;
    }

    ...
}

在 deployerConfigContext.xml 中:

<bean id="singleRowJdbcPersonMultiplyAttributeDao"
          class="com.scentbird.SingleRowJdbcPersonMultiplyAttributeDao">
        <constructor-arg index="0" ref="dataSource" />
        <constructor-arg index="1" value="SELECT attributes_table1.*, attributes_table2.attr1, attributes_table2.roles AS roles FROM user_table ut LEFT JOIN roles_table rt ON <condition> LEFT JOIN another_table at ON <condition> WHERE {0}" />
    <property name="queryAttributeMapping">
        <map>
            <entry key="username" value="username" />
        </map>
    </property>
</bean>

同样在我的情况下,我使用了 SAML 协议。

结果,您将在客户端上获得您选择返回的所有属性。例如,如果用户有很多角色,您可以在客户端上拥有:

用户:用户名、名字、姓氏、电子邮件、...、[ROLE_1、ROLE_2、ROLE_3]

我的案例适用于 Spring Security 和 Grails。

我不确定这是 100% 的风水解决方案 :) 因为它煮得很快,但它适用于我们的情况。

希望能帮助到你。

于 2016-04-22T08:36:04.363 回答
2

我刚刚花了三天时间尝试正确配置 CAS。我遇到的问题之一是我必须明确指示 CAS 发布属性。我这样做是:

  1. 打开https://localhost/cas/services
  2. 转到“管理服务”选项卡
  3. 单击每个服务的“编辑”
  4. 突出显示您要发布的属性
  5. 点击保存按钮

FWIW,另一个问题是 casServiceValidationSuccess.jsp 确实包含在响应中将属性传回的任何代码。当我发现你的问题时,我正在寻找解决方案。我注意到你已经重写了你的实现。

于 2011-05-23T17:53:56.310 回答
2

最终和完整的解决方案如下(对于这个未记录的功能):

  1. 服务器端:

    一个。添加一个attributeRepository到您的CredentialsToPrincipalResolver.

    湾。实现之your.package.YourPersonAttributeDao类的IPersonAttributeDao

    C。声明将被传输到断言中的属性给客户端。

    d。修改casServiceValidationSuccess.jsp以显示属性(thx to xiongjiabin)。

  2. 客户端。您可以通过执行以下操作获得所有属性:

    由于格式问题,我无法发布最终解决方案的代码……如果您有兴趣,请告诉我,我会向您发送一封包含所有代码的电子邮件。

于 2013-01-23T15:14:24.680 回答
1

除了@xiongjiabin 提供的答案,如果您使用的是 CAS v4+,您可能希望使用assertion.primaryAuthentication而不是assertion.chainedAuthenticationsin casServiceValidationSuccess.jsp

<cas:attributes>
    <c:forEach var="attr" items="${assertion.primaryAuthentication.principal.attributes}">
        <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>**
    </c:forEach>
</cas:attributes>

如果您确实assertion.chainedAuthentications与 CAS v4+ 一起使用,则将忽略serviceRegistryDao列表并返回所有属性。allowedAttributes

于 2015-12-11T05:21:41.357 回答