I use Spring 4 to create a simple application. Recently, I’m adding Spring Security 3 to the project but always get the Error Code 302 ( so it redirect to home page always ).
Here is my 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(); } }
I have a Controller called 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 ("error@1.1".equalsIgnoreCase(username)) { return "error"; } else { return "demo"; } } }
My WEB-INF structure:
WEB-INF ----views --------home.jsp --------demo.jsp --------error.jsp
The flow is like:
- User access the web site with
http://mylocal:8080/moon
=> it shows home.jsp - User press the button SignIn and it pops a sub-window asked for username and password => still in home.jsp
- User press Submit button => I assume it will go /acct/signin and return to /demo, but I see Error 302 in Google Chrome and then it goes to /home again
Any ideas ? I’m stuck in 2 full days and now i’m almost in despair…
thank you very much every one to take a look at my problem
=================================== 1st Update ===================================
Update: The form in 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>
=================================== 2nd Update ===================================
I tried to implement UserDetailsService(not to use in-memory auth) but still… the same problem – Error 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; } }; }
The log shows:
[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 ========
Advertisement
Answer
I believe Spring is redirecting you to /home
because you didn’t actually authenticated a User through the login process.
- You access your web-app through
http://mylocal:8080/moon
returning the home.jsp view - You click the SignIn button, submitting your login form
since no form login is explicitly declared, Spring Security will display the username and password prompt box for the end-user to enter its credentials - These credentials are then POSTed to the login processing URL (
/acct/signin
) for which you happen to have a mapping with thesignin
method in theAccountController
- Such controller fails to authenticate a User the Spring way, but still redirect the request to
/demo
by returning a String - The
/demo
path is protected (.anyRequest().authenticated()
) to any unauthenticated user, since the current user is indeed unauthenticated, Spring Security will automatically redirect the request to the login page - You end up on
/home
(.loginPage("/home")
)
Using a InMemoryUserDetailsManagerConfigurer (see inMemoryAuthentication javadoc), you can only successfully login through the configured credentials. If you want a fully-fledged Authentication system, you must provide an UserDetailsService implementation to your Spring Security configuration (through the userDetailsService method).
EDIT : Following the conversation with chialin.lin, it seems the missing configuration was a defaultSuccessfulUrl for Spring Security to know where to redirect the user once authenticated.