Ответ 1
Я потратил довольно много времени, обворачивая голову вокруг spring -security при использовании чистой конфигурации java. Есть несколько шагов, связанных с тем, чтобы это работало. Это должно быть что-то в этом роде. Основной процесс следующий:
-
Создание настраиваемых фильтров для проверки запросов для конкретной информации о авторизации
-
Каждый фильтр возвращает null (если авторизация этого типа не найдена) или пользовательский AbstractAuthenticationToken
-
Если фильтр возвращает токен, каждый метод аутентификации AuthenticationProvider будет вызван с этим токеном, возвращающим true | false, если он должен попробовать аутентификацию
-
tryAuthentication будет вызываться на AuthenticationProvider, который поддерживает токен. Здесь вы выполняете любые служебные вызовы для аутентификации пользователя. Затем вы можете вывести LoginException или вызвать authentication.setAuthenticated(true) и вернуть токен для успешной аутентификации.
Я использую эту установку некоторое время, поддерживая различные методы аутентификации (подписанный запрос, имя пользователя/пароль, oauth и т.д.), и он работает очень хорошо.
Вы также можете передать AuthenticationSuccessHandler и AuthenticationFailuersHandler в пользовательские фильтры безопасности для предоставления настраиваемых стратегий перенаправления и обработки ошибок.
Также не забудьте настроить макеты ant в конструкторах фильтра, чтобы контролировать, какие шаблоны url применяют фильтры. Например, фильтр запросов ldap, вероятно, нужно будет проверять с помощью любого запроса "/*", тогда как фильтр имени пользователя/пароля можно просто проверить на POST для входа/входа или чего-то подобного.
Пример кода:
1) Создайте пользовательский AuthenticationToken для каждого типа аутентификации, который вы хотите поддерживать
public class LDAPAuthorizationToken extends AbstractAuthenticationToken {
private String token;
public LDAPAuthorizationToken( String token ) {
super( null );
this.token = token;
}
public Object getCredentials() {
return token;
}
public Object getPrincipal() {
return null;
}
}
public class OTPAuthorizationToken extends UsernamePasswordAuthenticationToken {
private String otp;
public OTPAuthorizationToken( String username, String password, String otp ) {
super( username, password );
this.otp = otp;
}
public String getOTP() {
return otp;
}
}
2) Создайте настраиваемые фильтры безопасности для каждого типа
public class LDAPAuthorizationFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private UserDetailsService userDetailsService;
public LDAPAuthorizationFilter() {
super( "/*" ); // allow any request to contain an authorization header
}
public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response ) throws AuthenticationException
{
if ( request.getHeader( "Authorization" ) == null ) {
return null; // no header found, continue on to other security filters
}
// return a new authentication token to be processed by the authentication provider
return new LDAPAuthorizationToken( request.getHeader( "Authorization" ) );
}
}
public class OTPAuthorizationFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private UserDetailsService userDetailsService;
public OTPAuthorizationFilter() {
super( "/otp_login" );
}
public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response ) throws AuthenticationException
{
if ( request.getParameter( "username" ) == null || request.getParameter( "password" ) == null || request.getParameter( "otp" ) == null ) {
return null;
}
// return a new authentication token to be processed by the authentication provider
return new OTPAuthorizationToken( request.getParameter( "username" ), request.getParameter( "password" ), request.getParameter( "otp" ) );
}
}
3) Создайте пользовательские AuthenticationProviders
public class LDAPAuthenticationProvider implements AuthenticationProvider {
@Autowired
private MyAuthenticationService sampleService;
@Override
public Authentication authenticate( Authentication authentication ) throws AuthenticationException {
LDAPAuthorizationToken auth = (LDAPAuthorizationToken)authentication;
String username = sampleService.verifyToken( auth.getCredentials() );
if ( username == null ) {
throw new LoginException( "Invalid Token" );
}
auth.setAuthenticated( true );
return auth;
}
@Override
public boolean supports( Class<?> authentication ) {
if ( authentication.isAssignableFrom( LDAPAuthorizationToken.class ) ) {
return true;
}
return false;
}
}
public class OTPAuthenticationProvider implements AuthenticationProvider {
@Autowired
private MyAuthenticationService sampleService;
@Override
public Authentication authenticate( Authentication authentication ) throws AuthenticationException {
OTPAuthorizationToken auth = (OTPAuthorizationToken)authentication;
String error = sampleService.loginWithOTP( auth.getPrincipal(), auth.getCredentials(), auth.getOTP() );
if ( error != null ) {
throw new LoginException( error );
}
auth.setAuthenticated( true );
return auth;
}
@Override
public boolean supports( Class<?> authentication ) {
if ( authentication.isAssignableFrom( OTPAuthorizationToken.class ) ) {
return true;
}
return false;
}
}
4) Настроить spring безопасность
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure( HttpSecurity http ) throws Exception {
// configure filters
http.addFilterBefore( new LDAPAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class );
http.addFilterBefore( new OTPAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class );
// configure authentication providers
http.authenticationProvider( new LDAPAuthenticationProvider() );
http.authenticationProvider( new OTPAuthenticationProvider() );
// disable csrf
http.csrf().disable();
// setup security
http.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and().httpBasic();
}
}
Надеюсь, что это поможет!