web-dev-qa-db-fra.com

Spring Security 3 - renvoie toujours l'erreur 302

J'utilise Spring 4 pour créer une application simple. Récemment, j'ajoute Spring Security 3 au projet, mais j'obtiens toujours le code d'erreur 302 (pour qu'il soit toujours redirigé vers home page).

Voici mon SecurityConfig :

@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages = { "com.moon.repository" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser("hello").password("world").roles("USER");
}

@Override
public void configure(WebSecurity web) throws Exception {
    web
    .ignoring().antMatchers("/resources/**", "/views/**");
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()
            .antMatchers("/","/home").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/home")
            .loginProcessingUrl("/acct/signin")
            .and()
            .logout()
            .permitAll();
}

}

J'ai un contrôleur appelé AccountController :

@Controller
@RequestMapping(value = "/acct")
public class AccountController {

private final Logger logger = LoggerFactory.getLogger(AccountController.class);

@RequestMapping(value = "/signin", method = RequestMethod.POST)
public String signin(@RequestParam("username") String username,
        @RequestParam("password") String password) {

    logger.info("======== [username:{0}][password:{1}] ========", username, password);

    if ("[email protected]".equalsIgnoreCase(username)) {
        return "error";
    } else {
        return "demo";
    }
}

}

Ma structure WEB-INF:

WEB-INF
----views
--------home.jsp
--------demo.jsp
--------error.jsp

Le flux est comme:

  1. L'utilisateur accède au site Web avec http://mylocal:8080/moon => il montre home.jsp
  2. L'utilisateur appuie sur le bouton SignIn . Une sous-fenêtre demandant le nom d'utilisateur et le mot de passe => reste dans home.jsp
  3. L'utilisateur appuie sur le bouton Soumettre => Je suppose qu'il va aller/acct/se connecter et revenir à/démo, mais je vois l'erreur 302 dans Google Chrome, puis le message revient à/à la maison

Des idées ? Je suis coincé dans 2 jours complets et maintenant je suis presque désespéré ...

merci beaucoup à chacun de jeter un oeil à mon problème

================================== 1ère mise à jour =========== ========================

Mise à jour: Le formulaire dans home.jsp

<form:form role="form" method="POST" action="acct/signin"
class="form-signin">
<div class="row">
    <div class="col-lg-5">
        <input name="username" size="20" type="email"
            class="form-control" placeholder="Email address" required
            autofocus> 
            <input name="password" type="password"
                    class="form-control" placeholder="Password" required>
                <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
    </div>
</div>
</form:form>

================================== 2ème mise à jour =========== ========================

J'ai essayé d'implémenter UserDetailsService (ne pas utiliser d'authentification en mémoire) mais quand même ... le même problème - Erreur 302

AppUserDetailsServiceImpl.Java

@Component
public class AppUserDetailsServiceImpl implements UserDetailsService {

    private final Logger logger = LoggerFactory.getLogger(AppUserDetailsServiceImpl.class);

    @Override
    public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {

        logger.info("loadUserByUsername username=" + username);
        logger.info("======== {} ========",SecurityContextHolder.getContext().getAuthentication());

        if (!username.equals("hello")) {
            throw new UsernameNotFoundException(username + " not found");
        }

        // creating dummy user details
        return new UserDetails() {

            private static final long serialVersionUID = 2059202961588104658L;

            @Override
            public boolean isEnabled() {
                return true;
            }

            @Override
            public boolean isCredentialsNonExpired() {
                return true;
            }

            @Override
            public boolean isAccountNonLocked() {
                return true;
            }

            @Override
            public boolean isAccountNonExpired() {
                return true;
            }

            @Override
            public String getUsername() {
                return username;
            }

            @Override
            public String getPassword() {
                return "world";
            }

            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                List<SimpleGrantedAuthority> auths = new Java.util.ArrayList<SimpleGrantedAuthority>();
                auths.add(new SimpleGrantedAuthority("USER"));
                return auths;
            }
        };
    }

Le journal montre:

[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](24) loadUserByUsername username=hello
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](25) ======== org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f1e4f742: Principal: com.moon.repository.AppUserDetailsServiceImpl$1@e3dc1b1; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@12afc: RemoteIpAddress: 127.0.0.1; SessionId: 023BC9A8B997ECBD826DD7C33AF55FC7; Granted Authorities: USER ========
11
chialin.lin

Je crois que Spring vous redirige vers /home car vous n'avez pas authentifié un utilisateur via le processus de connexion.

  1. Vous accédez à votre application Web via http://mylocal:8080/moon en renvoyant la vue home.jsp.
  2. Vous cliquez sur le bouton Connexion pour soumettre votre formulaire de connexion. comme aucun identifiant de formulaire n'est explicitement déclaré, Spring Security affiche le nom d'utilisateur et le mot de passe. Boîte de dialogue d'invite permettant à l'utilisateur final de saisir ses informations d'identification
  3. Ces informations d'identification sont ensuite POSTÉES dans l'URL de traitement de la connexion (/acct/signin) pour laquelle vous avez un mappage avec la méthode signin dans la variable AccountController.
  4. Un tel contrôleur ne parvient pas à authentifier un utilisateur de la manière Spring, mais redirige néanmoins la demande vers /demo en renvoyant une chaîne.
  5. Le chemin d'accès /demo est protégé (.anyRequest().authenticated()) par tout utilisateur non authentifié, étant donné que l'utilisateur actuel n'est pas authentifié. Spring Security redirige automatiquement la demande vers la page de connexion.
  6. Vous vous retrouvez sur /home (.loginPage("/home"))

Avec un InMemoryUserDetailsManagerConfigurer (voir inMemoryAuthentication javadoc), vous ne pouvez vous connecter que par le biais des informations d'identification configurées. Si vous souhaitez un système d'authentification à part entière, vous devez fournir une implémentation UserDetailsService à votre configuration Spring Security (via la méthode userDetailsService ).


EDIT: Suite à la conversation avec chialin.lin, il semble que la configuration manquante soit un defaultSuccessfulUrl pour que Spring Security sache où rediriger l’utilisateur une fois authentifié.

7
m4rtin

Pour moi, je viens d'un cas d'utilisation légèrement différent, mais «tout à coup» a eu le même problème avant que cela ne fonctionne parfaitement.
Ma configuration Spring avec une interface ExtJs où je construis maintenant une interface de repos.
Tout a fonctionné super Nice et puis tout à coup, j'ai commencé à avoir http status 302 réponses (WTH?)

Depuis que j'ai implémenté par code en suivant cet exemple: https://octoperf.com/blog/2018/03/08/securing-rest-api-spring-security/
il existe une déclaration de SimpleUrlAuthenticationSuccessHandler .
Voir 4.4 SecurityConfig où le TokenAuthenticationFilter est construit avec une classe NoRedirectStrategy ; voir 4.1 Stratégie de redirection

À son tour, n'ayant pas cette NoRedirectStrategy configurée dans mon extension de AbstractAuthenticationProcessingFilter , elle me montrerait http 302 réponses.

0
Dirk Schumacher

Pour éviter de créer une nouvelle SuccessHandler triviale, substituez la méthode successfulAuthentication dans votre filtre et appelez simplement la méthode chain.doFilter() après avoir défini l'objet Authentication dans le contexte de sécurité.

0
Dani