AngularJS spring security login/logout with Cross-Origin Resource Sharing (CORS)

Posted

技术标签:

【中文标题】AngularJS spring security login/logout with Cross-Origin Resource Sharing (CORS)【英文标题】: 【发布时间】:2016-02-17 09:39:13 【问题描述】:

问题说明:我的 UI 应用程序在 9000 端口(grunt 项目)上运行,而我的服务器端 Spring Boot 项目在 8421 端口上运行。除了登录和注销之外,我可以从我的 UI 应用程序中访问所有 URL。请让我知道如何使用 CORS 配置 Spring Security 登录和注销。

App.js

  $scope.login = function() 
        $http.post('http://localhost:8421/login', $.param($scope.credentials), 
          headers : 
            'content-type' : 'application/x-www-form-urlencoded'
          
        ).success(function() 
          console.log('login success');
          );
        ).error(function() 
          console.log('login error');
        );
      ;

SecurityConfiguration.java

public class SecurityConfiguration extends WebSecurityConfigurerAdapter 

@Override
    protected void configure(HttpSecurity http) throws Exception 

        http.addFilterBefore(new SimpleCORSFilter(), ChannelProcessingFilter.class)
        .authorizeRequests().antMatchers("/rest/**").permitAll()
        .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
        .logoutSuccessUrl("/index.html")        
        .and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)       
        .and().formLogin().successHandler(authenticationSuccessHandler)
        .and().formLogin().failureHandler(authenticationFailureHandler)         
        .and().csrf().disable();
    

@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 

        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    

SimpleCORSFilter.java

public class SimpleCORSFilter implements Filter 
@Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

        chain.doFilter(req, res);
    

    @Override
    public void init(FilterConfig filterConfig) 

    

    @Override
    public void destroy() 

    

login.html

<form>
<div class="rb-form-group" ng-class=" 'has-error' : userForm.username.$invalid && !userForm.username.$pristine ">
            <input type="text" name="username" class="form-control" ng-model="credentials.username" placeholder="enter your username" required>
        </div>

        <!-- PASSWORD -->
        <div class="rb-form-group" ng-class=" 'has-error' : userForm.password.$invalid && !userForm.password.$pristine ">
            <input type="password" name="password" class="form-control" ng-model="credentials.password" placeholder="enter your password" required>        
        </div>

        <div class="rb-form-group">
            <button class="btn btn-primary btn-block" ng-disabled="userForm.$invalid" ng-click="login()">Login</button>        
        </div>
</form>

提前致谢

网络日志

Remote Address:[::1]:8421
Request URL:http://localhost:8421/login
Request Method:POST
Status Code:200 OK
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods:POST, GET, PUT, OPTIONS, DELETE
Access-Control-Allow-Origin:*
Access-Control-Max-Age:3600
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Length:0
Date:Tue, 17 Nov 2015 04:01:57 GMT
Expires:0
Pragma:no-cache
Server:Apache-Coyote/1.1
Set-Cookie:JSESSIONID=D22C05E81D4FC86EA32BD6545F2B37FF; Path=/; HttpOnly
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block
Request Headers
view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:31
content-type:application/x-www-form-urlencoded
Host:localhost:8421
Origin:http://localhost:9000
Referer:http://localhost:9000/src/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36

【问题讨论】:

保持简单,在你的 Spring Web 服务器中运行前端并使用相同的端口和协议。如果您真的真的需要使用 CORS,请发布网络日志。特别是对登录 URI 的请求(方法:OPTION 和 POST) @Michael:感谢您的回复。我已经用网络日志更新了我的问题以进行登录。请看一看。 是的,CORS 是必要的,因为我们正在为不同的客户构建相同的企业应用程序。所以我们需要解耦所有的东西。 你在使用带有 web.xml 配置的 tomcat 吗? 我很困惑 - 您的日志显示对 localhost:8421/login 的 POST 请求请求返回状态代码:200 OK。到底是什么不起作用? 【参考方案1】:

关于CORS问题,请将authorizationclient-security-token添加到Access-Control-Allow-Headers header,如下所示。

response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type, origin, authorization, accept, client-security-token");

如果您的 CORS 过滤器配置正确,这应该可以正常工作!

对于在 Spring Security 中使用基于 AJAX 的登录,您可能希望采用稍微不同的方法。此处对此进行了解释:

Spring security 3 Ajax login – accessing protected resources Implementing Ajax Authentication

希望对您有所帮助,如有任何问题,请随时发表评论!

【讨论】:

【参考方案2】:

我在 AngularJS 和 Spring 应用程序上完成了这个问题。这很简单。只需添加过滤器

public class CORSFilter extends OncePerRequestFilter 

    private final Logger LOG = LoggerFactory.getLogger(CORSFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException 
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        res.setHeader("Access-Control-Max-Age", "3600");
        res.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
        res.addHeader("Access-Control-Expose-Headers", "xsrf-token");
        if ("OPTIONS".equals(req.getMethod())) 
         res.setStatus(HttpServletResponse.SC_OK);
         else  
         chain.doFilter(req, res);
                
    

来自angularjs spring cross-origin request blocked的帖子

【讨论】:

以上是关于AngularJS spring security login/logout with Cross-Origin Resource Sharing (CORS)的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security AngularJS 登录

如何使用angularjs登录到spring security

使用 Spring Security 和 AngularJS 预防 CSRF

Spring Security 401 - 使用 / Angularjs 调用 restful 服务

将 Spring Security 添加到现有 Spring AngularJS 应用程序

如何使用 Spring Security 和 Angularjs 保护 Spring Rest 服务?