J'essaie de créer une application Web qui fournira principalement une API REST) à l'aide de Spring et tente de configurer le côté sécurité.
J'essaie d'implémenter ce type de modèle: https://developers.google.com/accounts/docs/MobileApps (Google a totalement changé cette page, elle n'a donc plus de sens - voir la page I faisait référence à: http://web.archive.org/web/20130822184827/https://developers.google.com/accounts/docs/MobileApps )
Voici ce que je dois accompagner:
(par exemple, connexions utilisateur/inscription à l'aide de formulaires normaux, webapp fournit un cookie sécurisé avec un jeton qui peut ensuite être utilisé dans les demandes d'API suivantes)
J'ai eu une configuration d'authentification normale comme ci-dessous:
@Override protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/mobile/app/sign-up").permitAll()
.antMatchers("/v1/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/loginprocess")
.failureUrl("/?loginFailure=true")
.permitAll();
}
Je pensais ajouter un filtre de pré-autorisation, qui vérifie la présence du jeton dans la demande, puis définit le contexte de sécurité (cela voudrait-il dire que l'authentification suivante sera ignorée?). Cependant, au-delà de mon utilisateur/mot de passe normal pas trop en ce qui concerne la sécurité basée sur les jetons, mais en me basant sur d’autres exemples, j’ai proposé ce qui suit:
Configuration de sécurité:
@Override protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilter(restAuthenticationFilter())
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and()
.antMatcher("/v1/**")
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/mobile/app/sign-up").permitAll()
.antMatchers("/v1/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/loginprocess")
.failureUrl("/?loginFailure=true")
.permitAll();
}
Mon filtre de repos personnalisé:
public class RestAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public RestAuthenticationFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
private final String HEADER_SECURITY_TOKEN = "X-Token";
private String token = "";
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
this.token = request.getHeader(HEADER_SECURITY_TOKEN);
//If we have already applied this filter - not sure how that would happen? - then just continue chain
if (request.getAttribute(FILTER_APPLIED) != null) {
chain.doFilter(request, response);
return;
}
//Now mark request as completing this filter
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
//Attempt to authenticate
Authentication authResult;
authResult = attemptAuthentication(request, response);
if (authResult == null) {
unsuccessfulAuthentication(request, response, new LockedException("Forbidden"));
} else {
successfulAuthentication(request, response, chain, authResult);
}
}
/**
* Attempt to authenticate request - basically just pass over to another method to authenticate request headers
*/
@Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
AbstractAuthenticationToken userAuthenticationToken = authUserByToken();
if(userAuthenticationToken == null) throw new AuthenticationServiceException(MessageFormat.format("Error | {0}", "Bad Token"));
return userAuthenticationToken;
}
/**
* authenticate the user based on token, mobile app secret & user agent
* @return
*/
private AbstractAuthenticationToken authUserByToken() {
AbstractAuthenticationToken authToken = null;
try {
// TODO - just return null - always fail auth just to test spring setup ok
return null;
} catch (Exception e) {
logger.error("Authenticate user by token error: ", e);
}
return authToken;
}
Ce qui précède entraîne en réalité une erreur au démarrage de l'application en disant: authenticationManager must be specified
Quelqu'un peut-il me dire comment le faire au mieux - un filtre de pré-authentification est-il le meilleur moyen de le faire?
[~ # ~] éditer [~ # ~]
J'ai écrit ce que j'ai trouvé et comment je l'ai fait avec Spring-security (y compris le code) en implémentant une implémentation de jeton standard (pas OAuth)
Vue d'ensemble du problème et approche/solution
Implémentation de la solution avec Spring-security
J'espère que ça aide les autres ..
Je crois que l'erreur que vous mentionnez est simplement due au fait que la classe de base AbstractAuthenticationProcessingFilter
que vous utilisez nécessite un AuthenticationManager
. Si vous ne l'utilisez pas, vous pouvez le définir sur une opération n °-op ou simplement implémenter Filter
directement. Si votre Filter
peut authentifier la demande et configurer le SecurityContext
, le traitement en aval sera généralement ignoré (cela dépend de la mise en œuvre des filtres en aval, mais je ne vois rien de bizarre dans votre application, donc ils se comportent probablement tous de cette façon).
Si j'étais vous, je pourrais envisager de placer les points de terminaison de l'API dans une chaîne de filtrage complètement séparée (un autre bean WebSecurityConfigurerAdapter
.). Mais cela ne fait que rendre les choses plus faciles à lire, pas nécessairement cruciales.
Vous constaterez peut-être (comme le suggèrent les commentaires) que vous finissez par réinventer la roue, mais que vous essayez de rien, et que vous en apprendrez davantage sur Spring et la sécurité.
ADDITION: le approche github est très intéressant: les utilisateurs utilisent simplement le jeton comme mot de passe dans l’authentification de base, et le serveur n’a pas besoin de filtre personnalisé (BasicAuthenticationFilter
, ça va).