从 CAS 获取更多属性而不仅仅是用户 ID

发布于 2024-10-15 19:03:15 字数 87 浏览 3 评论 0原文

我将 CAS 与 JDBC 身份验证处理程序一起使用,想知道是否可以在成功身份验证后获取主体对象的其他属性(例如名字、姓氏),而不仅仅是从 CAS 获取用户名?

I am using CAS with JDBC Authentication handler and was wondering is it possible to get the other attributes of principal object (for e.g. firstname, lastname) not just the username from CAS after successful authentication?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

沦落红尘 2024-10-22 19:03:15

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文件,请关闭浏览器,否则更改将不起作用。当心。

In the casServiceValidationSuccess.jsp, I add like below:

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

In the deployerConfigContent.xml, I add like below:

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

It works.
I came across this problem during the debug, please close the browser if you change this JSP or XML files, otherwise the changes won't work. Be careful.

听闻余生 2024-10-22 19:03:15

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

<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% 的风水解决方案:),因为它煮得很快,但在我们的情况下它有效。

希望有帮助。

To get any user attributes from DB I did the following:
use PersonDirectoryPrincipalResolver

in deployerConfigContext.xml:

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

instead of using standard SingleRowJdbcPersonAttributeDao class create your own implementation which returns not only one row from a query result but aggregated data from all returned rows:

copy all code from SingleRowJdbcPersonAttributeDao and change only one method parseAttributeMapFromResults.
you will have something like that:

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

    ...
}

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

Also in my case I used SAML protocol.

As a result you will get on the client all attributes which your select returns.
For example, if user have many roles you could have on the client:

User: username, firstname, lastname, email, ... , [ROLE_1, ROLE_2, ROLE_3]

My case works with Spring Security and Grails.

I'm not sure this is 100% Feng Shui solution :) as it's fast cooked but it works in our case.

Hope it helps.

浅暮の光 2024-10-22 19:03:15

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

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

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

I just spent the last three days attempting to get CAS properly configured. One of the issues I encountered was that I had to explicitly instruct CAS to publish the properties. I did this by:

  1. opening https://localhost/cas/services
  2. going to the 'Manage Services' tab
  3. click 'edit' for each service
  4. highlight the properties you wish to publish
  5. click the save button

FWIW, the other issue is that casServiceValidationSuccess.jsp does contain any code to pass the properties back in the response. I was looking for a solution to this when I found your question. I notice that you have rewritten your implementation.

鹿港巷口少年归 2024-10-22 19:03:15

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

  1. 服务器端:

    a.将 attributeRepository 添加到您的 CredentialsToPrincipalResolver

    b.像 IPersonAttributeDao 一样实现 your.package.YourPersonAttributeDao

    c.声明将传输到客户端的断言的属性。

    d.修改casServiceValidationSuccess.jsp以显示属性(感谢xiongjiabin)。

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

    <块引用>

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

    客户

The definitive and complete solution is the following (for this undocumented feature):

  1. Server side:

    a. Add an attributeRepository to your CredentialsToPrincipalResolver.

    b. Implement the your.package.YourPersonAttributeDao like an IPersonAttributeDao.

    c. Declare the attributes that will be transmitted into assertion to client.

    d. Modify the casServiceValidationSuccess.jsp to display the attributes (thx to xiongjiabin).

  2. Client side. You get all attributes by doing this:

    Due to formatting problem I can't post the code of the definitive solution.... Let me know if you are interested, I will send you an email with all the code.

你穿错了嫁妆 2024-10-22 19:03:15

除了 @xiongjiabin 提供的答案之外,如果您使用 CAS v4+,您可能希望在 casServiceValidationSuccess.jsp< 中使用 assertion.primaryAuthentication 而不是 assertion.chainedAuthentications /code>:

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

如果您在 CAS v4+ 中使用 assertion.chainedAuthentications,则 allowedAttributesserviceRegistryDao 列表将被忽略,并且所有属性都将被返回。

In addition to the answer provided by @xiongjiabin if you are using CAS v4+ you probably want to use assertion.primaryAuthentication instead of assertion.chainedAuthentications in 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>

If you do use assertion.chainedAuthentications with CAS v4+ then the serviceRegistryDao list of allowedAttributes will be ignored and all attributes will be returned.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文