Получение большего количества атрибутов из CAS, чем просто идентификатор пользователя
Я использую CAS с обработчиком проверки подлинности JDBC и задаюсь вопросом, возможно ли получить другие атрибуты основного объекта (например, firstname, lastname) не только имя пользователя из CAS после успешной аутентификации?
Ответы
Ответ 1
В 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 файлы, иначе изменения не будут работать. Будьте осторожны.
Ответ 2
Чтобы получить какие-либо пользовательские атрибуты из БД, я сделал следующее:
используйте 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% решение Feng Shui:), поскольку оно быстро готовится, но оно работает в нашем случае.
Надеюсь, что это поможет.
Ответ 3
Я только что провел последние три дня, пытаясь правильно настроить CAS. Одна из проблем, с которыми я столкнулась, заключалась в том, что я должен был явно указать CAS для публикации свойств. Я сделал это:
- открытие https://localhost/cas/services
- переход на вкладку "Управление службами"
- нажмите "изменить" для каждой службы.
- выделите свойства, которые вы хотите опубликовать.
- нажмите кнопку сохранения
FWIW, другая проблема заключается в том, что casServiceValidationSuccess.jsp содержит любой код для передачи свойств в ответ. Я искал решение этого вопроса, когда нашел свой вопрос. Я замечаю, что вы переписали свою реализацию.
Ответ 4
Окончательное и полное решение является следующим (для этой недокументированной функции):
-
Серверная сторона:
а. Добавьте attributeRepository
к вашему CredentialsToPrincipalResolver
.
б. Внесите your.package.YourPersonAttributeDao
как IPersonAttributeDao
.
с. Объявите атрибуты, которые будут переданы в утверждение клиенту.
д. Измените casServiceValidationSuccess.jsp
, чтобы отобразить атрибуты (спасибо to xiongjiabin).
-
Клиентская сторона. Вы получаете все атрибуты, делая это:
Из-за проблемы с форматированием я не могу опубликовать код окончательного решения.... Сообщите мне, если вы заинтересованы, я пришлю вам письмо со всем кодом.
Ответ 5
В дополнение к ответу, предоставленному @xiongjiabin, если вы используете CAS v4 +, вы, вероятно, захотите использовать assertion.primaryAuthentication
вместо assertion.chainedAuthentications
в 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
будет проигнорирован и все атрибуты будут возвращены.