Java Spring Security 3 - 总是返回错误 302

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25357518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:11:53  来源:igfitidea点击:

Spring Security 3 - always return error 302

javaspringspring-mvcspring-security

提问by chialin.lin

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 homepage always ).

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

Here is my SecurityConfig:

这是我的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:

我有一个名为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";
    }
}

}

My WEB-INF structure:

我的 WEB-INF 结构:

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

The flow is like:

流程是这样的:

  1. User access the web site with http://mylocal:8080/moon=> it shows home.jsp
  2. User press the button SignInand it pops a sub-window asked for username and password => still in home.jsp
  3. 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
  1. 用户使用http://mylocal:8080/moon=>访问网站,它显示home.jsp
  2. 用户按下按钮签到,它会弹出一个子窗口询问用户名和密码=>仍然回到Home.jsp
  3. 用户按下提交按钮 => 我认为它会转到 /acct/signin 并返回到 /demo,但我在 Google Chrome 中看到错误 302,然后它又转到 /home

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

更新: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

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

AppUserDetailsServiceImpl.java

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

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@e3dc1b1; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@12afc: RemoteIpAddress: 127.0.0.1; SessionId: 023BC9A8B997ECBD826DD7C33AF55FC7; Granted Authorities: USER ========

采纳答案by m4rtin

I believe Spring is redirecting you to /homebecause you didn't actually authenticated a User through the login process.

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

  1. You access your web-app through http://mylocal:8080/moonreturning the home.jsp view
  2. 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
  3. These credentials are then POSTed to the login processing URL (/acct/signin) for which you happen to have a mapping with the signinmethod in the AccountController
  4. Such controller fails to authenticate a User the Spring way, but still redirect the request to /demoby returning a String
  5. The /demopath 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
  6. You end up on /home(.loginPage("/home"))
  1. 您通过http://mylocal:8080/moon返回 home.jsp 视图来访问您的网络应用程序
  2. 您单击“登录”按钮,提交您的登录表单 由于没有显式声明表单登录,Spring Security 将显示用户名和密码提示框供最终用户输入其凭据
  3. 然后,这些凭据发布到登录处理URL( /acct/signin),而您正好有与映射signin的方法AccountController
  4. 此类控制器无法以 Spring 方式对用户进行身份验证,但仍/demo通过返回字符串将请求重定向到
  5. /demo路径被保护(.anyRequest().authenticated())对任何未认证用户,因为当前的用户确实是未经认证的使用,Spring Security会自动将请求重定向到登录页面
  6. 你最终在/home( .loginPage("/home"))

Using a InMemoryUserDetailsManagerConfigurer(see inMemoryAuthenticationjavadoc), you can only successfully login through the configured credentials. If you want a fully-fledged Authentication system, you must provide an UserDetailsServiceimplementation to your Spring Security configuration (through the userDetailsServicemethod).

使用InMemoryUserDetailsManagerConfigurer(请参阅inMemoryAuthenticationjavadoc),您只能通过配置的凭据成功登录。如果你想要一个成熟的认证系统,你必须为你的 Spring Security 配置提供一个UserDetailsS​​ervice实现(通过userDetailsS​​ervice方法)。



EDIT : Following the conversation with chialin.lin, it seems the missing configuration was a defaultSuccessfulUrlfor Spring Security to know where to redirect the user once authenticated.

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

回答by Dani

To avoid having to create a new trivial SuccessHandler, override the successfulAuthenticationmethod in your filter and just call the chain.doFilter()method after having set the Authenticationobject in the security context.

为避免创建新的 trivial SuccessHandler,请覆盖successfulAuthentication过滤器中的chain.doFilter()方法,并Authentication在安全上下文中设置对象后调用该方法。

回答by Dirk Schumacher

For me I came from a little different use-case but 'suddenly' had the same problem before it perfectly worked.
My Setup Spring with a ExtJs frontend where I now build in a rest interface.
It all worked super nice and then suddenly I started having http status 302responses (WTH?)

对我来说,我来自一个有点不同的用例,但在它完美工作之前“突然”遇到了同样的问题。
我的设置 Spring 带有 ExtJs 前端,我现在在其中构建了一个休息界面。
这一切都非常好,然后突然间我开始收到http 状态 302响应(WTH?)

Since I implemented by code by following this example: https://octoperf.com/blog/2018/03/08/securing-rest-api-spring-security/
there is a declaration of a SimpleUrlAuthenticationSuccessHandler.
See 4.4 SecurityConfigwhere the TokenAuthenticationFilteris constructed with a class NoRedirectStrategy; see 4.1 Redirect Strategy

由于我通过以下示例通过代码实现:https: //octoperf.com/blog/2018/03/08/securing-rest-api-spring-security/
有一个SimpleUrlAuthenticationSuccessHandler的声明。
参见4.4 SecurityConfig,其中TokenAuthenticationFilter是用类NoRedirectStrategy 构造的;见4.1 重定向策略

In turn not having this NoRedirectStrategyset up in my extension of the AbstractAuthenticationProcessingFilterit would show me http 302responses.

反过来,如果没有在我的AbstractAuthenticationProcessingFilter扩展中设置这个NoRedirectStrategy,它会向我显示http 302响应。