Angularjs Can';t设置具有Angular和Spring安全性的身份验证标头

Angularjs Can';t设置具有Angular和Spring安全性的身份验证标头,angularjs,spring,cors,Angularjs,Spring,Cors,我很难让Angular、CORS、SpringSecurity和基本身份验证很好地发挥作用。我有下面的Angular Ajax调用,其中我试图将头设置为在请求中包含基本授权头 var headerObj = {headers: {'Authorization': 'Basic am9lOnNlY3JldA=='}}; return $http.get('http://localhost:8080/mysite/login', headerObj).then(function (response)

我很难让Angular、CORS、SpringSecurity和基本身份验证很好地发挥作用。我有下面的Angular Ajax调用,其中我试图将头设置为在请求中包含基本授权头

var headerObj = {headers: {'Authorization': 'Basic am9lOnNlY3JldA=='}};
return $http.get('http://localhost:8080/mysite/login', headerObj).then(function (response) {
    return response.data;
});
我在localhost:8888上运行angular应用程序,在localhost:8080上运行后端服务器。所以我不得不在我的服务器端添加一个CORS过滤器,即SpringMVC。所以我创建了一个过滤器并将其添加到我的web.xml中

web.xml

<filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.abcinsights.controller.SimpleCorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<display-name>ABC Insights</display-name>
<servlet>
    <servlet-name>abcInsightsServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/config/servlet-config.xml</param-value>
    </init-param> 
</servlet>
<servlet-mapping>
    <servlet-name>abcInsightsServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!--  Stand Alone Cross Origin Resource Sharing Authorization Configuration -->
<filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.abcinsights.controller.SimpleCorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>       
<!--  Spring Security Configuration -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/config/security-config.xml</param-value>
</context-param>    
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

克斯菲尔特
com.abcinsights.controller.SimpleCorsFilter
克斯菲尔特
/*
克斯菲尔特

public class SimpleCorsFilter extends OncePerRequestFilter {

@Override
public void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
    Enumeration<String> headerNames = req.getHeaderNames();
    while(headerNames.hasMoreElements()){
        String headerName = headerNames.nextElement();
        System.out.println("headerName " + headerName);
        System.out.println("headerVal " + req.getHeader(headerName));
    }               
    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type, Authorization");
    chain.doFilter(req, res);
}   
}
公共类SimpleCorsFilter扩展了OncePerRequestFilter{
@凌驾
public void doFilterInternal(HttpServletRequest-req、HttpServletResponse-res、FilterChain-chain)抛出IOException、ServletException{
枚举headerNames=req.getHeaderNames();
while(headerNames.hasMoreElements()){
字符串headerName=headerName.nextElement();
System.out.println(“headerName”+headerName);
系统输出打印项次(“headerVal”+request.getHeader(headerName));
}               
HttpServletResponse=(HttpServletResponse)res;
response.setHeader(“访问控制允许原点“,“*”);
setHeader(“访问控制允许方法”、“POST、GET、OPTIONS、DELETE”);
setHeader(“访问控制最大年龄”,“3600”);
response.setHeader(“访问控制允许标头”、“来源、X请求的权限、内容范围、内容处置、内容类型、授权”);
链式过滤器(要求、恢复);
}   
}
这一切都很好,当我查看头名称/值时,我会看到带有基本值和硬编码Base64字符串的授权头

因此,我尝试添加SpringSecurity,它将使用授权头进行基本身份验证。这是我的web.xml和添加了spring安全性的spring安全配置

更新的web.xml

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/config/security-config.xml</param-value>
</context-param>

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

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

org.springframework.web.context.ContextLoaderListener
上下文配置位置
/WEB-INF/config/security-config.xml
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
security-config.xml

<http auto-config="true" use-expressions="false">
    <intercept-url pattern="/**" access="ROLE_USER" />
    <http-basic/>
    <custom-filter ref="corsHandler" before="SECURITY_CONTEXT_FILTER"/>
</http>

<beans:bean id="corsHandler" class="com.abcinsights.controller.SimpleCorsFilter"/>

<authentication-manager>
    <authentication-provider>
        <jdbc-user-service data-source-ref="dataSource"/>
    </authentication-provider>
</authentication-manager>

如您所见,我必须将我的CORS过滤器添加到spring安全过滤器链的前端(我还将其从web.xml中删除)。当我发出请求时,CORS过滤器仍然会被调用,从这个意义上说,这似乎是可行的。但是来自AJAX调用的请求不再添加授权头。当我移除SpringSecurity过滤器链并将我的CORS过滤器放回web.xml时,授权头就会回来。我不知所措,但我想知道这是否与飞行前通信有关,当我的CORS过滤器在web.xml中是独立的时,一种方式工作,另一种方式是在Spring安全过滤器链中工作?任何帮助都将不胜感激


谢谢

问题在于angular在没有HTTP授权头的情况下发送HTTP选项请求。Spring security随后处理该请求并发回401未经授权的响应。因此,我的angular应用程序收到spring对选项请求的401响应,而不是告诉angular继续发送包含授权标头的POST请求的200响应。所以解决办法是

a) 将我的CORSFilter和我的SpringSecurity过滤器放在web.xml中(而不是从Spring中调用我的CORS过滤器)。不是100%确定这会有什么不同,但这就是我最终的web.xml的样子

b) 将下面链接中的代码添加到my CORS筛选器中,这样就不会将选项请求类型委托给SpringSecurity

这篇文章让我理清了思路:

这是我的密码:

web.xml

<filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.abcinsights.controller.SimpleCorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<display-name>ABC Insights</display-name>
<servlet>
    <servlet-name>abcInsightsServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/config/servlet-config.xml</param-value>
    </init-param> 
</servlet>
<servlet-mapping>
    <servlet-name>abcInsightsServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!--  Stand Alone Cross Origin Resource Sharing Authorization Configuration -->
<filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.abcinsights.controller.SimpleCorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>       
<!--  Spring Security Configuration -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/config/security-config.xml</param-value>
</context-param>    
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
这是我的角度代码:

var login = function (credentials) {
    console.log("credentials.email: " + credentials.email);
    console.log("credentials.password: " + credentials.password);

    var base64Credentials = Base64.encode(credentials.email + ':' + credentials.password);

    var req = {
        method: 'GET',
        url: 'http://localhost:8080/abcinsights/loginPage',
        headers: {
            'Authorization': 'Basic ' + base64Credentials
        }
    }

    return $http(req).then(function (response) {
        return response.data;
    });        
};

希望这会有帮助。

参加聚会有点晚,但我遇到了类似的问题,我想我的解决方案可能会对某人有所帮助。乔·赖斯的溶液确实对我有帮助,但我不得不做一些修改。我还应该提到,我不是Spring或Tomcat方面的专家,所以这可能不是一个完美的解决方案

我有一个带有React客户端(在localhost:3000上运行)、Tomcat服务器(localhost:8080)和Spring安全性的设置。我必须让Tomcat处理CORS头,因为我有两个.war文件在应用服务器上运行:我的应用程序和Geowebcache。对我来说,让Spring安全性处理头文件是不够的,因为这意味着当客户端直接与Geowebcache通信时,不会添加头文件

我还使用了一个用Spring安全性实现的登录页面。使用Tomcat“CorsFilter”可以很好地处理所有常规请求,但由于某些原因,CORS头没有添加到客户端的登录请求中,导致浏览器阻止响应,因为缺少“Access Control Allow Origin”头。对此,我的解决方案是手动将头添加到来自客户端的登录调用中,并让Tomcat配置处理其余部分。这是我的设置

Spring安全性-web.xml:

<filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>path.to.cors.filter.security.SimpleCorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
SimpleCorsFilter.java:

public class SimpleCorsFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    if (request.getRequestURI().endsWith("perform_login")) {
        response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type, Authorization, X-CSRF-TOKEN");
    }

    chain.doFilter(req, res);
}
Tomcat-web.xml

<filter>
  <filter-name>CorsFilter</filter-name>
  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
  <init-param>
    <param-name>cors.allowed.origins</param-name>
    <param-value>http://localhost:3000</param-value>
  </init-param>
  <init-param>
    <param-name>cors.support.credentials</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>cors.exposed.headers</param-name>
    <param-value>Content-Disposition,Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CorsFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

希望这能帮助别人

尝试在筛选器中添加
@Order(Ordered.HIGHEST\u priority)
注释。谢谢您的建议。不幸的是,这似乎没有帮助。是的,因为您使用的是不同的配置。我的另一个建议是更改安全过滤器链中的位置:
axios.create({
  baseURL: process.env.NODE_ENV === 'development' ? 'http://localhost:8080/api/' : '/api/',
  timeout: 300000,
  withCredentials: true
});