【问题标题】:Spring Boot Rest Spring Security Authentication Issue with CORS使用 CORS 的 Spring Boot Rest Spring 安全身份验证问题
【发布时间】:2017-04-16 01:44:56
【问题描述】:

我正在使用 Spring Boot 开发一个 Spring REST 应用程序。我正在使用 Angular JS 客户端使用 Spring REST API。

我正在使用的堆栈是:

Spring Boot 1.4.2 , Spring Security , Angular JS , Tomcat 8 

我的问题是:

1) 登录时,用户成功通过身份验证。自定义身份验证成功处理程序返回 200 状态码。

2)认证成功后,当clint再次发送请求访问受保护的资源时,HttpSession为NULL

3)因此当SecurityContextPersistenceFilter 尝试从HttpSession 检索SecurityContext 时,它会返回为null 并且 然后服务器再次向/login资源发送请求

4)所以我的问题是:

1) 为什么第二个请求的 httpsesion 为空?

2)我观察到 Spring security 在第一次成功验证后返回 JSESSIONID 作为 cookie。

3)但是在那之后,客户端不会在请求中发送这个JSESSIONID,因此第二个请求不会在同一个会话中。

4) 如果是这样的话,如果SESSION 不成立,如何检索SecurityContext

请帮忙,因为我无法在这里继续

编辑 1:

我正在使用 spring security 提供的默认内存用户。我的安全配置如下:

@Configuration
@EnableWebSecurity
@ComponentScan({"com.atul.security"})
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private RESTAuthenticationSuccessHandler authenticationSuccessHandler;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
          http
            .formLogin().successHandler(authenticationSuccessHandler)
            .and()
            .csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS,"/*").permitAll()
            .antMatchers("/index.html", "/home.html", "/login.html", "/").permitAll()
            .anyRequest().authenticated()
            .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

}

我作为经过身份验证的用户低于用户:

org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: 
Principal: anonymousUser; Credentials: [PROTECTED]; 
Authenticated: true; 
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: 
RemoteIpAddress: 0:0:0:0:0:0:0:1; 
SessionId: null; 
Granted Authorities: ROLE_ANONYMOUS

请求现在失败:AbstractSecurityInterceptorAccessDecisionVoterauthenticated 表达式返回 false 并抛出拒绝访问异常

【问题讨论】:

  • 您是否禁用了 csrf 令牌安全性?
  • 是的,我在配置 Spring Security 时这样做了
  • @Atul : 你知道这个意思吗 :and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  • 是的。这意味着spring security永远不会创建会话,这意味着基于表单的登录将不起作用。我将删除 STATELESS 并尝试

标签: spring-boot spring-rest


【解决方案1】:

因为 RESTFUL 服务不维护状态,所以没有会话处于静止状态,阅读此堆栈溢出帖子:

Do sessions really violate RESTfulness?

如果您想知道如何正确构建基于 REST 的 spring 安全服务,请查看本教程:

http://www.baeldung.com/securing-a-restful-web-service-with-spring-security

希望这会有所帮助。

您正在使用 formLogin 安全性,这意味着您需要添加某种数据存储来对用户进行身份验证。

这是来自 Spring 文档的内存数据存储示例:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public UserDetailsService userDetailsService() throws Exception {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
    manager.createUser(User.withUsername("user").password("password").roles("USER").build());
    manager.createUser(User.withUsername("admin").password("password").roles("USER","ADMIN").build());
    return manager;
}

}

根据这个例子,你假设使用用户名用户名和密码密码成功验证

您正在尝试使用 angularJS 作为前端技术来应用安全性,有一个很棒的教程如何实现它,我已经在我的项目中实现了它,这是链接:

https://spring.io/guides/tutorials/spring-security-and-angular-js/

首先,您需要使用 httpBasic 而不是 formLogin 作为您的安全认证方法。

【讨论】:

  • 我尝试过使用 sessionCreationPolicy(SessionCreationPolicy.STATELESS)。请求现在通过 UsernamePasswordAuthenticationFilter。问题是: .anyRequest().authenticated() 现在返回 false 并抛出拒绝访问异常。
  • 你有任何数据源(内存或数据库)来验证你的用户吗?
  • 我使用的是 Spring Security - Spring Boot 提供的默认用户。
  • 请发布您的堆栈跟踪和安全配置文件
  • Moshe 还是一样的例外。我尝试了 inMemoryAuthentication 设置,并且用户成功通过了身份验证。问题是身份验证后的第二个请求仍然给匿名用户。基于表单的身份验证需要会话,因此我不能使用 STATELESS 子句。我也试过了,但仍然是同样的例外
【解决方案2】:

敲了半天头,终于找到解决办法了。

步骤是: 1) 基于表单的登录需要建立会话。认证成功后,服务器会发送Set-Cookie:JSESSIONID=3974317C6DE34865B6726FCFD4C98C08; Path=/springbootrest; HttpOnly header作为响应。

2)浏览器必须在每个请求中发送此标头,否则将无法建立会话并且身份验证将失败

3) 但是由于我使用的是CORS(我的服务器和ui 应用程序驻留在本地系统的不同端口上),所以浏览器没有在请求中发送Cookie:JSESSIONID=3974317C6DE34865B6726FCFD4C98C08 身份验证失败。

4) 在浏览器开始在请求中发送上面的标头后,我必须在我的 Angular js 客户端中添加下面的行 $httpProvider.defaults.withCredentials = true;

5) 在服务器端,我必须在 CORSFilter 中添加以下代码。

 response.setHeader("Access-Control-Allow-Credentials","true");
        response.setHeader("Access-Control-Allow-Origin", "http://localhost:8186");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, WWW-Authenticate, Authorization, Origin, Content-Type, Version");
        response.setHeader("Access-Control-Expose-Headers", "X-Requested-With, WWW-Authenticate, Authorization, Origin, Content-Type");

       final HttpServletRequest request = (HttpServletRequest) req;
       if("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-13
    • 2019-02-21
    • 2020-05-22
    • 2019-04-25
    • 2019-03-13
    • 1970-01-01
    • 2017-03-28
    • 2011-05-04
    相关资源
    最近更新 更多