Ответ 1
Мне пришлось выполнить аналогичный двухэтапный процесс аутентификации. Это звучит просто, но поиск правильных мест для инъекций и правильные методы для переопределения были непростыми. Основная идея заключается в предоставлении другой роли промежуточной проверки подлинности (проверка электронной почты), а затем предоставление полного доступа после подтверждения электронной почты.
Надеюсь, что приведенный ниже код содержит некоторые полезные советы о том, как он может быть разрешен для вашего сценария.
Создайте пользовательский UserDetailsChecker для обработки проверок после аутентификации. Здесь определяется роль пользователя.
public class CustomPostAuthenticationChecks implements UserDetailsChecker {
public void check(UserDetails userDetails) {
CustomUser customUser = (CustomUser) userDetails;
if (customUser.needsEmailAuthentication()) {
// Get rid of any authorities the user currently has
userDetails.getAuthorities().clear();
// Set the new authority, only allowing access to the
// email authentication page.
userDetails.getAuthorities().add(new GrantedAuthorityImpl("ROLE_NEEDS_EMAIL_AUTH"));
} else {
userDetails.getAuthorities().add(new GrantedAuthorityImpl("ROLE_AUTHORIZED_USER"));
}
}
Создайте пользовательский аутентификаторSuccessHandler. Этот класс отправляет пользователя на правильный URL-адрес на основе их роли.
public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Override
protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
String targetUrl = null;
SecurityContext securityContext = SecurityContextHolder.getContext();
Collection<GrantedAuthority> authorities = securityContext.getAuthentication().getAuthorities();
if (authorities.contains(new GrantedAuthorityImpl("ROLE_NEEDS_EMAIL_AUTH"))) {
targetUrl = "/authenticate";
} else if (authorities.contains(new GrantedAuthorityImpl("ROLE_AUTHORIZED_USER"))) {
targetUrl = "/authorized_user_url";
} else {
targetUrl = super.determineTargetUrl(request, response);
}
return targetUrl;
}
После того, как адрес электронной почты пользователя будет аутентифицирован, вам необходимо предоставить пользователю полный доступ к приложению:
public void grantUserAccess(User user) {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication auth = securityContext.getAuthentication();
user.getAuthorities().clear();
user.getAuthorities().add(new GrantedAuthorityImpl("ROLE_AUTHORIZED_USER"));
Authentication newAuth = new UsernamePasswordAuthenticationToken(user, auth.getCredentials(), user.getAuthorities());
securityContext.setAuthentication(newAuth);
}
Определите поставщика пользовательской проверки подлинности, чтобы зарегистрировать свой CustomPostAuthenticationChecks:
<security:authentication-manager>
<security:authentication-provider ref="customAuthenticationProvider" />
</security:authentication-manager>
<bean id="customAuthenticationProvider" class="YourAuthenticationProvider">
<property name="postAuthenticationChecks">
<bean class="CustomPostAuthenticationChecks"/>
</property>
</bean>
Если вы используете стандартный тег для входа в форму, вы можете легко определить свой пользовательский AuthenticationSuccessHandler:
<security:form-login authentication-success-handler-ref="customAuthenticationSuccessHandler">
...
<bean id="customAuthenticationSuccessHandler" class="CustomAuthenticationSuccessHandler"/>
Добавьте новое правило перехвата роли для URL /authenticate, поэтому только пользователи, которым требуется больше аутентификации, могут получить доступ к этой странице.
<security:intercept-url pattern="/authenticate/**" access="hasRole('ROLE_NEEDS_EMAIL_AUTH')" />
<security:intercept-url pattern="/authorized_user_url/**" access="hasRole('ROLE_AUTHORIZED_USER')" />