当前位置: 首页 > 知识库问答 >
问题:

Spring Security,REST基本身份验证问题

孙梓
2023-03-14

在Spring中使用基本身份验证时,我遇到了与HTTP响应标头“Access-Control-Allow-Origin”相关的问题。当我手动进行身份验证时,就像下面的代码一样(我使用的是REST):

@RequestMapping(value = "/login", method = RequestMethod.POST, consumes = "application/json")
@ResponseStatus(value = HttpStatus.OK)
public void login(@RequestBody String body, HttpServletResponse response)
        throws IOException {
    try {
        User user = gson.fromJson(body, User.class);

        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                usuario.getUsername(), usuario.getPassword());

        authenticationManager.authenticate(token);
    } catch (BadCredentialsException e) {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    } catch (Exception e) {
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }
}

一切正常,我收到以下HTTP响应:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
Content-Type: text/html;charset=utf-8
Content-Length: 951
Date: Fri, 17 May 2013 19:14:36 GMT

如您所见,响应中出现了“Access-Control-Allow-Origin”。这里一切都好。我可以在ajax调用中捕捉到401错误。

但是,当身份验证自动执行时,就像下面的代码一样:

@RequestMapping(value = "/name", method = RequestMethod.POST, consumes = "application/json")
@PreAuthorize("hasRole('ROLE_CUSTOMER')")
public @ResponseBody String getName(HttpServletResponse response) throws IOException {
    String json = null;

    try {
        User userSession = (User) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();

        Customer customer = customerDao.getNameByUsername(userSession.getUsername());

        json = gson.toJson(customer);

    } catch (Exception e) {
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }

    return json;
}

HTTP响应是:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
WWW-Authenticate: Basic realm="Spring Security Application"
Content-Type: text/html;charset=utf-8
Content-Length: 981
Date: Fri, 17 May 2013 19:41:08 GMT

响应中没有“访问控制允许原点”

Google Chrome控制台显示以下错误:

Origin null is not allowed by Access-Control-Allow-Origin

我的ajax调用没有返回401未授权错误,即使HTTP响应返回它(上面的响应),我也会收到一个未知错误。

我弄清楚了,对于所有浏览器,我在HTTP响应中需要一个“Access-Control-Allo-Origin”,否则它们会产生某种静默错误,我的ajax调用会失败(抓不到401错误)。实际上,javascript会静默失败。XMLHttpRequest不接受没有“Access-Control-Allo-Origin”的HTTP响应。

如何让Spring在基本认证的HTTP响应中注入这个“Access-Control-Allow-Origin ”?

这是我的Spring Securityxml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
          http://www.springframework.org/schema/security
          http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <security:http create-session="stateless" entry-point-ref="authenticationEntryPoint">
        <security:intercept-url pattern="/customer/**" />
        <security:http-basic />
        <security:custom-filter ref="basicAuthenticationFilter"
            after="BASIC_AUTH_FILTER" />
    </security:http>

    <bean id="basicAuthenticationFilter"
        class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
    </bean>

    <bean id="authenticationEntryPoint"
        class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
        <property name="realmName" value="teste.com" />
    </bean>

    <!-- It is responsible for validating the user's credentials -->
    <security:authentication-manager alias="authenticationManager">

        <!-- It is responsible for providing credential validation to the AuthenticationManager -->
        <security:authentication-provider>
            <security:password-encoder ref="passwordEncoder" />

            <security:jdbc-user-service
                data-source-ref="mySQLdataSource"
                users-by-username-query="select username, password, enabled from usuario where username = ?"
                authorities-by-username-query="select username, papel from autoridade where username = ?" />

        </security:authentication-provider>

    </security:authentication-manager>

    <bean class="org.springframework.security.crypto.password.StandardPasswordEncoder"
        id="passwordEncoder" />

</beans>

共有1个答案

万俟光临
2023-03-14

只是找到了自己的路:

首先,我真的不记得为什么我把这一行放在这里,但它弄乱了我的代码:

<security:http-basic />

其次,这个答案向我展示了路径:在Spring Security中处理基本身份验证的未经授权的错误消息。我必须创建一个自定义身份验证切入点才能发送访问控制允许起源的东西。

这是我现在的代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
              http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
              http://www.springframework.org/schema/security
              http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <security:http create-session="stateless"
        entry-point-ref="authenticationEntryPoint">
        <security:intercept-url pattern="/api/admin/**" />
        <security:intercept-url pattern="/medico/**" />
        <!-- <security:http-basic />  -->
        <security:custom-filter ref="basicAuthenticationFilter"
            after="BASIC_AUTH_FILTER" />
    </security:http>

    <bean id="basicAuthenticationFilter"
        class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
    </bean>

            <!-- 
    <bean id="authenticationEntryPoint" 
        class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
        <property name="realmName" value="test.com" />
    </bean> -->


    <bean id="authenticationEntryPoint" 
        class="com.test.util.PlainTextBasicAuthenticationEntryPoint">
        <property name="realmName" value="test.com" />
    </bean> 

    <!-- It is responsible for validating the user's credentials -->
    <security:authentication-manager alias="authenticationManager">

        <!-- It is responsible for providing credential validation to the AuthenticationManager -->
        <security:authentication-provider>
            <security:password-encoder ref="passwordEncoder" />

            <security:jdbc-user-service
                data-source-ref="mySQLdataSource"
                users-by-username-query="select username, password, enabled from usuario where username = ?"
                authorities-by-username-query="select username, papel from autoridade where username = ?" />

        </security:authentication-provider>

    </security:authentication-manager>

    <bean
        class="org.springframework.security.crypto.password.StandardPasswordEncoder"
        id="passwordEncoder" />

</beans>
package com.test.util;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;

public class PlainTextBasicAuthenticationEntryPoint extends
        BasicAuthenticationEntryPoint {

      @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
            response.addHeader("Access-Control-Allow-Origin", "null");
            response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\"");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            PrintWriter writer = response.getWriter();
            writer.println("HTTP Status " + HttpServletResponse.SC_UNAUTHORIZED + " - " + authException.getMessage());
        }

}

我现在的http响应:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: null
WWW-Authenticate: Basic realm="test.com"
Content-Length: 35
Date: Mon, 20 May 2013 20:05:03 GMT

HTTP Status 401 - Bad credentials

在更改之前,我收到此错误消息:

OPTIONS http://localhost:8080/test/customer/name 200 (OK) jquery-1.8.2.min.js:2
XMLHttpRequest cannot load http://localhost:8080/test/customer/name. Origin null is     not allowed by Access-Control-Allow-Origin. 

现在正如预期的那样,我得到了这个:

OPTIONS http://localhost:8080/test/customer/name 200 (OK) jquery-1.8.2.min.js:2
POST http://localhost:8080/test/customer/name 401 (Unauthorized) 
 类似资料:
  • 我试图使用curl检索jira问题从我的公司服务器没有任何运气到目前为止。 我已经测试了这里描述的两个示例JIRA REST API示例-基本身份验证,但没有成功。我对我的用户和密码进行了base64编码,如“提供基本身份验证头”示例中所述,并输入了我想要获得的问题的url。我在浏览器中测试了url,得到了json文档,因此url是正确的。 这就是我的命令 someuser@somehost:~$

  • 问题是当我尝试验证: 正文: 我总是有一个401错误状态,因为我的自定义入口点。在我看来,spring security并没有调用Authentication-Manager。我错过什么了吗?

  • 为了测试,我尝试下面的代码过滤包含用户的url参数,但是它没有在未经授权的情况下中止请求。最重要的是,我需要以这样的方式来实现它,即只有更新和删除需要用各自的用户名和密码来授权。其他我只是不想过滤的东西。我有一个user类,它具有username和password(加密)属性。因此,如果url包含Users/{userID}的PUT或delete方法,我希望它使用特定用户的用户名和密码进行验证。我

  • 问题内容: 从HttpClient 4.3开始,我一直在使用HttpClientBuilder。我正在连接到具有基本身份验证的REST服务。我将凭据设置如下: 但是,这不起作用(我正在使用的REST服务返回401)。怎么了? 问题答案: 从此处的 抢先身份验证 文档中: http://hc.apache.org/httpcomponents-client- ga/tutorial/html/aut

  • 我不熟悉RESTful API的概念。 我正在为一家在线商店设计一个RESTful API。 我没有正确理解SSL上的基本HTTP身份验证的概念。 这是否意味着对于每个请求,用户都必须再次输入他/她的用户名和密码? 有人能详细解释它的功能和用途吗?

  • 目前我正在开发一个Java工具,它应该可以更新Confluence服务器页面。使用Curl一切都像一个符咒,但是当使用Postman或Java代码(HttpClient Java11)时,我得到了一个 HTTP状态401–未经授权 反应。 在下面的语句中使用curl curl--basic-u user:password-X PUT-H“内容类型:application/json”-d“@test