【问题标题】:AngularJS $Http CORS with backend in Spring Rest & SecurityAngularJS $Http CORS 与 Spring Rest & Security 中的后端
【发布时间】:2014-07-10 07:18:10
【问题描述】:

我对 AngularJS 有疑问。当我从另一个域调用 Rest Services 时,授权标头未在请求中发送,因此 Spring Security 无法识别身份验证凭据。附上配置文件。

web.xml

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>

<filter>
<filter-name>cors</filter-name>
<filter-class>com.axcessfinancial.web.filter.CorsFilter</filter-class>

<filter-mapping><filter-name>cors</filter-name><url-pattern>/*</url-pattern></filter-mapping>

Context-Security.xml

<http use-expressions="true">
    <intercept-url pattern="/**" access="isAuthenticated()" />
    <http-basic/>   
</http>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="admin" password="admin" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
</authentication-manager>

CorsFilter

protected void doFilterInternal(HttpServletRequest request,
        HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    response.addHeader("Access-Control-Allow-Origin", "*");
    if (request.getHeader("Access-Control-Request-Method") != null  && "OPTIONS".equals(request.getMethod())) {
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Authorization, Accept, Content-Type, X-PINGOTHER");
        response.addHeader("Access-Control-Max-Age", "1728000");
    }
    filterChain.doFilter(request, response);
}

app.js

var app = angular.module('app', ['app.controller','app.services']);
app.config(function($httpProvider) {    
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];  
    /* $httpProvider.defaults.headers.common['Authorization'] = 'Basic YWRtaW46YWRtaW4='; */
});

service.js

angular.module('app.services',[]).service('Service', function ($http,$q,UtilHttp) {
    $http.defaults.headers.common = {"Access-Control-Request-Headers": "accept, origin, authorization"}; 
    $http.defaults.headers.common['Authorization'] = 'Basic YWRtaW46YWRtaW4=';

    return {
        listCutomer:  function(){
            var defer=$q.defer();
            $http.post('http://localhost:8088/rest-template/soa/listCustomer',{withCredentials: true})
            .success(function(data){
                defer.resolve(data);
            })
            .error(function(data){
                defer.reject(data);
            });
            return defer.promise;
        }
    };
});

问题:

Response Headersview source
Content-Length  1134
Content-Type    text/html;charset=utf-8
Date    Wed, 21 May 2014 14:39:44 GMT
Server  Apache-Coyote/1.1
Set-Cookie  JSESSIONID=5CD90453C2CD57CE111F45B0FBCB0301; Path=/rest-template
WWW-Authenticate    Basic realm="Spring Security Application"
Request Headers
Accept  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Access-Control-Request-He...    authorization,content-type
Access-Control-Request-Me...    POST
Cache-Control   no-cache
Connection  keep-alive
Host    localhost:8088
Origin  null
Pragma  no-cache
User-Agent  Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0

【问题讨论】:

  • 您可以尝试将 cors 过滤器映射定义放在 spring security 之前。这样,cors 过滤器应该在 spring security 之前执行。
  • 嗨,尼尔斯,感谢您的回答。我已尝试执行您在答案中提到的操作,但仍然遇到相同的错误。

标签: spring angularjs rest spring-mvc spring-security


【解决方案1】:

将您的过滤器添加到 Spring Security 过滤器链的前面...

<http>
   <custom-filter before="CHANNEL_FILTER" ref="myFilter" />
 </http> 

<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>

http://docs.spring.io/spring-security/site/docs/3.0.x/reference/ns-config.html

【讨论】:

    【解决方案2】:

    我认为您的问题如下:

    什么时候

    • 使用 GET 或 POST 以外的 HTTP 动词
    • 需要发送自定义标头(例如身份验证、X-API-Key 等)
    • 需要请求正文具有除 text/plain 以外的 MIME 类型

    您的浏览器(遵循 CORS 规范)向请求添加了一个额外步骤:

    它首先使用“OPTIONS”方法向 URL 发送一个特定请求,如果服务器响应批准您希望您的真正请求启动的实际请求。

    不幸的是,在您的场景中,spring 向 OPTIONS 请求返回 401(未经授权),因为此请求中不存在身份验证令牌,因此您的真正请求永远不会启动

    解决方案:

    如果请求方法是 OPTIONS,您可以将 cors 过滤器放在 web.xml 中的 spring 安全过滤器之前,并避免调用链中的下一个过滤器(spring security)

    这个例子过滤器对我有用:

    public class SimpleCORSFilter implements Filter {
    
    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-Credentials", "true");
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    
    }
    
    public void init(FilterConfig filterConfig) {
    }
    
    public void destroy() {
    }
    

    }

    记得在 web.xml 中的 spring 安全过滤器之前声明你的 cors 过滤器

    【讨论】:

    • 最后一行尤为重要。如果您使用注释而不是 web.xml,则应在类文件中在安全过滤器的注释方法之前声明 cors 过滤器的注释方法。
    【解决方案3】:

    当我使用 Spring Security 使用 web.xml 来配置项目时,我遇到了同样的问题,我按照所说的做了。下面过滤器中的 if 条件解决了我的问题。我使用带有 REST 和 Spring Security 的 Web.xml 的项目托管在

    https://github.com/leandrocprates/projetoSpring-Rest-JDBC-Security-Configuracao-WebXML

    数据库在:

    projetoSpring-Rest-JDBC-Security-Configuracao-WebXML/src/main/resources/script_tabelas/

    并且文件 angularjs.html 用于执行项目。它通过授权并返回一个json。点击按钮“busca empresa”。

    projetoSpring-Rest-JDBC-Security-Configuracao-WebXML/src/main/webapp/angularjs.html

    这个项目是 葡萄牙语 的人,但作为一个模型只是为了看看如何配置项目。

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

    【讨论】:

      猜你喜欢
      • 2019-09-24
      • 1970-01-01
      • 2021-10-30
      • 2015-03-22
      • 2017-02-19
      • 2014-04-12
      • 2018-03-06
      • 2019-07-06
      • 2015-11-13
      相关资源
      最近更新 更多