Я использую CAS с обработчиком проверки подлинности JDBC и задаюсь вопросом, возможно ли получить другие атрибуты основного объекта (например, firstname, lastname) не только имя пользователя из CAS после успешной аутентификации?
Получение большего количества атрибутов из 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
будет проигнорирован и все атрибуты будут возвращены.