Spring Security 3 - 始终返回错误302

chi*_*lin 13 java spring spring-mvc spring-security

我使用Spring 4创建一个简单的应用程序.最近,我将Spring Security 3添加到项目中,但总是得到错误代码302(因此它总是重定向到主页).

这是我的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();
}

}
Run Code Online (Sandbox Code Playgroud)

我有一个名为AccountController的Controller :

@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";
    }
}

}
Run Code Online (Sandbox Code Playgroud)

我的WEB-INF结构:

WEB-INF
----views
--------home.jsp
--------demo.jsp
--------error.jsp
Run Code Online (Sandbox Code Playgroud)

流程如下:

  1. 用户访问网站http://mylocal:8080/moon=>它显示home.jsp
  2. 用户按下SignIn按钮,弹出一个子窗口,询问用户名和密码=>仍然在home.jsp中
  3. 用户按提交按钮=>我认为它将进入/ acct/signin并返回/ demo,但我在Google Chrome中看到错误302然后再次进入/ home

有任何想法吗 ?我被困在整整两天,现在我几乎绝望了......

非常感谢每个人看看我的问题

===================================第一次更新============= ======================

更新: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>
Run Code Online (Sandbox Code Playgroud)

===================================第二次更新============= ======================

我试图实现UserDetailsS​​ervice(不使用内存中的auth)但仍然......同样的问题 - 错误302

AppUserDetailsS​​erviceImpl.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;
            }
        };
    }
Run Code Online (Sandbox Code Playgroud)

日志显示:

[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 ========
Run Code Online (Sandbox Code Playgroud)

m4r*_*tin 7

我相信Spring会重定向您,/home因为您实际上并未通过登录过程对用户进行身份验证.

  1. 您可以通过http://mylocal:8080/moon返回home.jsp视图来访问您的Web应用程序
  2. 单击"登录"按钮,提交登录表单 由于没有显式声明表单登录,因此Spring Security将显示用户名和密码提示框,供最终用户输入其凭据
  3. 然后将这些凭据POST到登录处理URL(/acct/signin),您正好为其中的signin方法映射AccountController
  4. 这样的控制器无法以Spring方式验证User,但仍然/demo通过返回String 来重定向请求
  5. /demo路径被保护(.anyRequest().authenticated())对任何未认证用户,因为当前的用户确实是未经认证的使用,Spring Security会自动将请求重定向到登录页面
  6. 你最终/home(.loginPage("/home"))

使用InMemoryUserDetailsManagerConfigurer(请参阅inMemoryAuthentication javadoc),您只能成功登录已配置的凭据.如果需要完全成熟的身份验证系统,则必须为Spring Security配置提供UserDetailsS​​ervice实现(通过userDetailsS​​ervice方法).


编辑:在与chialin.lin的对话之后,似乎缺少的配置是Spring Security 的defaultSuccessfulUrl,知道在经过身份验证后重定向用户的位置.