Spring Security – Authentification par authentification basée sur des jetons et authentification utilisateur / mot de passe

J’essaie de créer une application Web qui fournira principalement une API REST à l’aide de Spring, et j’essaie de configurer le côté de la 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, donc ce n’est plus logique – voir la page à laquelle je fais référence ici: http: //web.archive.org/web/20130822184827/https://developers.google.com/accounts/docs/MobileApps )

Voici ce que je dois accompagner:

  • L’application Web dispose de formulaires d’inscription et d’inscription simples qui fonctionnent avec une authentification utilisateur / mot de passe de spring normale (ont déjà fait ce genre de choses avec dao / authenticationmanager / userdetailsservice, etc.)
  • Les points de terminaison api REST qui sont des sessions sans état et chaque requête authentifiée basée sur un jeton fourni avec la demande

(par exemple, l’utilisateur se connecte / s’inscrit en utilisant des formulaires normaux, webapp fournit un cookie sécurisé avec un jeton qui peut ensuite être utilisé dans les demandes d’API suivantes)

J’avais une configuration d’authentification normale 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 append un filtre de pré-authentification, qui vérifie le jeton dans la requête et définit ensuite le contexte de sécurité (cela signifierait-il que l’authentification suivante normale serait ignorée?), Au-delà de l’utilisateur / mot de passe normal pas trop fait avec la sécurité basée sur les jetons, mais sur la base d’autres exemples, j’ai trouvé les éléments suivants:

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(Ssortingng defaultFilterProcessesUrl) { super(defaultFilterProcessesUrl); } private final Ssortingng HEADER_SECURITY_TOKEN = "X-Token"; private Ssortingng 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.getAtsortingbute(FILTER_APPLIED) != null) { chain.doFilter(request, response); return; } //Now mark request as completing this filter request.setAtsortingbute(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 fait une erreur au démarrage de l’application en disant: authenticationManager must be specified Quelqu’un peut-il me dire comment faire cela – un filtre pre_auth est-il le meilleur moyen de le faire?


MODIFIER

J’ai écrit ce que j’ai trouvé et comment je l’ai fait avec Spring-security (y compris le code) implémentant une implémentation de jeton standard (pas OAuth)

Vue d’ensemble du problème et approche / solution

Implémenter la solution avec Spring-security

J’espère que ça aide certains autres ..

Je crois que l’erreur que vous mentionnez est juste parce que la classe de base AbstractAuthenticationProcessingFilter que vous utilisez nécessite un AuthenticationManager . Si vous ne comptez pas l’utiliser, vous pouvez le définir comme un non-op ou simplement implémenter directement le Filter . Si votre Filter peut authentifier la requête et configurer SecurityContext le traitement en aval sera généralement ignoré (cela dépend de l’implémentation des filtres en aval, mais je ne vois rien de bizarre dans votre application, donc ils se comportent probablement tous de cette manière). ).

Si j’étais vous, je pourrais envisager de placer les points de terminaison de l’API dans une chaîne de filtres 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 pourriez trouver (comme suggéré dans les commentaires) que vous finissez par réinventer la roue, mais pas de mal à essayer, et vous en apprendrez probablement plus sur Spring et Security.

ADDITION: l’ approche github est assez intéressante: les utilisateurs utilisent simplement le jeton comme mot de passe dans l’authentification de base, et le serveur n’a pas besoin d’un filtre personnalisé ( BasicAuthenticationFilter convient bien).