使用AngularJS和Spring Boot的Post基本认证语义

Post Basic Authentication semantics with AngularJS and Spring Boot?

本文关键字:认证 语义 Post AngularJS Spring Boot 使用      更新时间:2023-09-26

我正在通读下面的教程。AngularJS的导航控制器在页面加载时触发,其中包括执行一个验证函数,如下所示:

var authenticate = function(credentials, callback) {
    var headers = credentials ? {
        authorization: "Basic " +
            btoa(credentials.username + ":" + credentials.password)
    } : {};
    $http.get('user', {
        headers: headers
    }).then(function(response) {
        if (response.data.name) {
            $rootScope.authenticated = true;
        } else {
            $rootScope.authenticated = false;
        }
        callback && callback();
    }, function() {
        $rootScope.authenticated = false;
        callback && callback();
    });
}

函数被这样调用:authenticate()

因此没有传递凭据或回调,因此在页面加载时身份验证显然没有成功。这样调用它的原因是在登录后浏览器刷新的情况下。所以我的问题是这个函数如何成功地将$rootScope.authenticated设置为真正的登录后,因为IIUC的基本身份验证headers值与ajax请求发送(行$http.get('user', {headers : headers})将是{}。Spring是否会简单地让请求通过,因为用户已经经过身份验证,这是因为Authentication Basic标头是在表单身份验证后设置的吗?

这里的重点是Spring Boot(实际上是Spring Security)在成功认证后在后端创建一个HttpSession

实际上,后端是有状态的,因为它在服务器端保留会话数据(身份验证的用户)。客户端(这里是浏览器)由提供的会话id标识。

从协议的角度来看,身份验证流是这样的。

用例:浏览器向后端发起HTTP调用:后端响应Unauthorized,因为客户端试图访问受保护的资源而没有Authorization

$ curl -I -H "X-Requested-With:XMLHttpRequest" http://localhost:8080/user
HTTP/1.1 401
Set-Cookie: XSRF-TOKEN=b1137571-5e15-491c-8df5-9db5d34f29a8;path=/
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Transfer-Encoding: chunked

用例:抢占式基本身份验证。后端授予对资源的访问权限,并通知客户端会话id

$ curl -I -H "X-Requested-With:XMLHttpRequest" -H "Authorization:Basic dXNlcjpwYXNzd29yZA==" http://localhost:8080/user
HTTP/1.1 200
Set-Cookie: XSRF-TOKEN=ef72f0b8-4262-4ea2-8a46-5f7e19558079;path=/
Set-Cookie: JSESSIONID=52B61923DE639EE339A653845FBFC5F2;path=/;HttpOnly
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type    : application/json;charset=UTF-8
Content-Length: 343

由于浏览器通过HTTP头Authorization发送有效的用户凭据,后端创建一个新的HttpSession并向浏览器发送一个标识符(会话id)

Set-Cookie: JSESSIONID=52B61923DE639EE339A653845FBFC5F2;path=/;HttpOnly

现在,浏览器自动将Cookie标头附加到每个后续的HTTP调用中

Cookie: JSESSIONID=52B61923DE639EE339A653845FBFC5F2

防止新的身份验证周期。只要会话在服务器端没有超时,服务器就会将会话数据"分配"给这个特定的HTTP请求。

基本认证并不局限于Spring Boot (Spring Security)和Angular。它是多年来Internet的标准化认证方案。

请记住,基本身份验证是一种老式的身份验证方案,在现代web应用程序中非常不受欢迎。

Spring是否会让请求通过,因为用户已经通过了身份验证,这是因为身份验证基本头是在表单身份验证后设置的吗?

关于上面的例子,你现在可以理解为什么一个空的headers对象不会导致拒绝。

  1. 浏览器(Angular应用)用有效的用户凭证设置了Authorization头抢占,并向受限资源发起HTTP请求
  2. 服务器验证用户凭据,创建由会话id标识的HttpSession并将其发送回浏览器
  3. 浏览器自动将会话id作为cookie附加到后续的每个HTTP请求中
  4. 服务器通过会话id识别HTTP请求并接受传入请求

如果你指示Spring Security不在服务器上创建会话会发生什么?为此,在

后面添加
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

to SecurityConfiguration::configure .

现在,您可以看到示例中对/resource的每次调用都会导致HTTP 401,因为服务器上不再有会话。现在,Angular应用必须自己在每个HTTP请求上设置Authorization标头。

浏览器也可以自动附加Authorization标头。为简洁起见,我将跳过这部分。请记住,基本身份验证在现代web应用程序中是非常不鼓励的。

这个例子的目的不是向你展示如何用Spring Boot和Angular实现登录。其主要目的是在微服务架构中,将原始登录进化为基于OAuth2和Spring的单点登录。

不要认为代码示例是理所当然的。