与Spring Security的跨源资源共享 [英] Cross-Origin Resource Sharing with Spring Security

查看:1124
本文介绍了与Spring Security的跨源资源共享的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使CORS与Spring Security发挥得很好,但它不符合。我进行了中描述的更改这篇文章和更改这行在 applicationContext-security.xml 有POST和GET请求为我的应用程序工作(暂时公开控制器方法,所以我可以测试CORS ):




  • 之前:< intercept-url pattern =/ **access =isAuthenticated />

  • 之后:< intercept-url pattern =/ **access =permitAll/&



不幸的是,以下URL允许Spring Security通过AJAX登录没有响应: http:// localhost:8080 / mutopia-server / resources / j_spring_security_check 。我正在从 http:// localhost:80 http:// localhost:8080 进行AJAX请求。 / p>

在Chrome中



尝试访问 j_spring_security_check 在Chrome中为OPTIONS预检请求返回(挂起),并返回HTTP状态代码0和消息error的AJAX调用。


$ b b

在Firefox



预检成功与HTTP状态代码302,我仍然得到我的AJAX请求的错误回调,然后直接HTTP状态0和消息错误。



>



>



AJAX请求代码



  function get(url,json){
var args = {
type:'GET',
url:url,
// async:false,
// crossDomain:true,
xhrFields:{
withCredentials :false
},
success:function(response){
console.debug(url,response);
},
error:function(xhr){
console.error(url,xhr.status,xhr.statusText);
}
};
if(json){
args.contentType ='application / json'
}
$ .ajax(args);
}

function post(url,json,data,dataEncode){
var args = {
type:'POST',
url:url ,
// async:false,
crossDomain:true,
xhrFields:{
withCredentials:false
},
beforeSend:function(xhr){
//默认情况下总是添加
//忽略这个可以防止preflight - 但是期望浏览器跟随302位置更改
xhr.setRequestHeader('X-Requested-With','XMLHttpRequest' );
xhr.setRequestHeader(X-Ajax-call,true);
},
success:function(data,textStatus,xhr){
// var location = xhr.getResponseHeader('Location');
console.error('success',url,xhr.getAllResponseHeaders());
},
error:function(xhr){
console.error(url,xhr.status,xhr.statusText);
console.error('fail',url,xhr.getAllResponseHeaders());
}
}
if(json){
args.contentType ='application / json'
}
if(typeof data!='undefined' ){
//在主体中发送JSON raw
args.data = dataEncode? JSON.stringify(data):data;
}
console.debug('args',args);
$ .ajax(args);
}

var loginJSON = {j_username:username,j_password:password};

//失败
post('http:// localhost:8080 / mutopia-server / resources / j_spring_security_check',false,loginJSON,false);

// Works
post('http:// localhost / mutopia-server / resources / j_spring_security_check',false,loginJSON,false);

// Works
get('http:// localhost:8080 / mutopia-server / landuses?projectId = 6',true);

// Works
post('http:// localhost:8080 / mutopia-server / params',true,{
name:testing,
local:false,
generated:false,
project:6
},true);请注意 - 除了Spring Security登录之外,我可以通过CORS POST到我应用程序中的任何其他网址。

我已经经历了很多文章,所以任何洞察这个奇怪的问题将非常感谢:)

解决方案

通过扩展UsernamePasswordAuthenticationFilter ...我的代码是在Groovy,希望这样做:

  public class CorsAwareAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
static final String ORIGIN ='Origin'

@Override
public Authentication attemptAuthentication(HttpServletRequest请求,HttpServletResponse响应){
if(request.getHeader(ORIGIN)){
String origin = request.getHeader(ORIGIN)
response.addHeader('Access-Control-Allow-Origin',origin)
response.addHeader('Access-Control-Allow-Methods' ,'GET,POST,PUT,DELETE')
response.addHeader('Access-Control-Allow-Credentials','true')
response.addHeader('Access-Control-Allow-Headers' ,
request.getHeader('Access-Control-Request-Headers'))
}
if(request.method =='OPTIONS'){
response.writer.print ('OK')
response.writer.flush()
return
}
return super.attemptAuthentication(request,response)
}
}

上面的重要位置:




  • 只有在检测到CORS请求时才将CORS标头添加到响应中

  • 使用简单的非空200响应(其中还包含CORS标头)响应飞行前OPTIONS请求。 / li>


您需要在Spring配置中声明这个bean。有很多文章显示如何做到这一点,我不会在这里复制。



在我自己的实现中,我使用源域白名单,因为我允许CORS仅供内部开发人员访问。以上是我所做的一个简化版本,因此可能需要调整,但这应该给你的一般想法。


I'm trying to make CORS play nicely with Spring Security but it's not complying. I made the changes described in this article and changing this line in applicationContext-security.xml has got POST and GET requests working for my app (temporarily exposes controller methods, so I can test CORS):

  • Before: <intercept-url pattern="/**" access="isAuthenticated()" />
  • After: <intercept-url pattern="/**" access="permitAll" />

Unfortunately the following URL which allows Spring Security logins through AJAX isn't responding: http://localhost:8080/mutopia-server/resources/j_spring_security_check. I am making the AJAX request from http://localhost:80 to http://localhost:8080.

In Chrome

When attempting to access j_spring_security_check I get (pending) in Chrome for the OPTIONS preflight request and AJAX call returns with HTTP status code 0 and message "error".

In Firefox

The preflight succeeds with HTTP status code 302 and I still get the error callback for my AJAX request directly afterwards with HTTP status 0 and message "error".

AJAX Request Code

function get(url, json) {
    var args = {
        type: 'GET',
        url: url,
        // async: false,
        // crossDomain: true,
        xhrFields: {
            withCredentials: false
        },
        success: function(response) {
            console.debug(url, response);
        },
        error: function(xhr) {
            console.error(url, xhr.status, xhr.statusText);
        }
    };
    if (json) {
        args.contentType = 'application/json'
    }
    $.ajax(args);
}

function post(url, json, data, dataEncode) {
    var args = {
        type: 'POST',
        url: url,
        // async: false,
        crossDomain: true,
        xhrFields: {
            withCredentials: false
        },
        beforeSend: function(xhr){
            // This is always added by default
            // Ignoring this prevents preflight - but expects browser to follow 302 location change
            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            xhr.setRequestHeader("X-Ajax-call", "true");
        },
        success: function(data, textStatus, xhr) {
            // var location = xhr.getResponseHeader('Location');
            console.error('success', url, xhr.getAllResponseHeaders());
        },
        error: function(xhr) {
            console.error(url, xhr.status, xhr.statusText);
            console.error('fail', url, xhr.getAllResponseHeaders());
        }
    }
    if (json) {
        args.contentType = 'application/json'
    }
    if (typeof data != 'undefined') {
        // Send JSON raw in the body
        args.data = dataEncode ? JSON.stringify(data) : data;
    }
    console.debug('args', args);
    $.ajax(args);
}

var loginJSON = {"j_username": "username", "j_password": "password"};

// Fails
post('http://localhost:8080/mutopia-server/resources/j_spring_security_check', false, loginJSON, false);

// Works
post('http://localhost/mutopia-server/resources/j_spring_security_check', false, loginJSON, false);

// Works
get('http://localhost:8080/mutopia-server/landuses?projectId=6', true);

// Works
post('http://localhost:8080/mutopia-server/params', true, {
    "name": "testing",
    "local": false,
    "generated": false,
    "project": 6
}, true);

Please note - I can POST to any other URL in my app via CORS except the Spring Security login. I've gone through lots of articles, so any insight into this strange issue would be greatly appreciated :)

解决方案

I was able to do this by extending UsernamePasswordAuthenticationFilter... my code is in Groovy, hope that's OK:

public class CorsAwareAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    static final String ORIGIN = 'Origin'

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
        if (request.getHeader(ORIGIN)) {
            String origin = request.getHeader(ORIGIN)
            response.addHeader('Access-Control-Allow-Origin', origin)
            response.addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
            response.addHeader('Access-Control-Allow-Credentials', 'true')
            response.addHeader('Access-Control-Allow-Headers',
                    request.getHeader('Access-Control-Request-Headers'))
        }
        if (request.method == 'OPTIONS') {
            response.writer.print('OK')
            response.writer.flush()
            return
        }
        return super.attemptAuthentication(request, response)
    }
}

The important bits above:

  • Only add CORS headers to response if CORS request detected
  • Respond to pre-flight OPTIONS request with a simple non-empty 200 response, which also contains the CORS headers.

You need to declare this bean in your Spring configuration. There are many articles showing how to do this so I won't copy that here.

In my own implementation I use an origin domain whitelist as I am allowing CORS for internal developer access only. The above is a simplified version of what I am doing so may need tweaking but this should give you the general idea.

这篇关于与Spring Security的跨源资源共享的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆