无法使用 Angular 和 Spring Security 设置身份验证标头

2024-04-13

我在让 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 上运行我的角度应用程序,在 localhost:8080 上运行我的后端服务器。所以我必须在我的服务器端(Spring MVC)添加一个 CORS 过滤器。所以我创建了一个过滤器并将其添加到我的 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>

过滤器

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);
}   
}

这一切都工作正常,当我查看标头名称/值时,我看到我的授权标头包含基本值和硬编码的 Base64 字符串。

然后我尝试添加 SpringSecurity ,它将使用 Authorization 标头进行基本身份验证。这是我的 web.xml 和 spring security 配置,添加了 Spring Security。

更新了 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>

安全配置.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 security 过滤器链的前面(我还从 web.xml 中将其删除)。这似乎是有效的,因为当我发出请求时,CORS 过滤器仍然会被调用。但是来自我的 AJAX 调用的请求不再添加 Authorization 标头。当我删除 SpringSecurity 过滤器链并将 CORS 过滤器放回到 web.xml 中时,Authorization 标头就会回来。我很茫然,但想知道当我的 CORS 过滤器在 web.xml 中独立时,它是否与预检通信以一种方式工作有关,而当它在 Spring Security 过滤器链中时,是否与另一种方式有关?任何帮助,将不胜感激。

Thanks


问题是 Angular 正在发送没有 HTTP 授权标头的 HTTP OPTIONS 请求。然后 Spring Security 处理该请求并发回 401 Unauthorized 响应。因此,我的 Angular 应用程序在 OPTIONS 请求上从 Spring 收到了 401 响应,而不是 200 响应,告诉 Angular 继续发送包含 Authorization 标头的 POST 请求。所以解决方法是

a) 将我的 CORSFilter 和 SpringSecurity 过滤器放入 web.xml 中(而不是从 Spring 中调用我的 CORS 过滤器)。不能 100% 确定这会产生影响,但这就是我最终的 web.xml 的样子。

b) 将以下链接中的代码添加到我的 CORS 过滤器中,以便它不会委托给 SpringSecurity 处理 OPTIONS 请求类型。

这篇文章让我整理了一下:独立 Spring OAuth2 JWT 授权服务器 + CORS https://stackoverflow.com/questions/30632200/standalone-spring-oauth2-jwt-authorization-server-cors/30638914#30638914

这是我的代码:

web.xml

<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>

这是我的 CORS 过滤器:

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;       
        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, X-CSRF-TOKEN");  

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

这是我的角度代码:

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;
    });        
};

希望有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法使用 Angular 和 Spring Security 设置身份验证标头 的相关文章

随机推荐