Angular 登录后无法获取令牌

Angular 登录后无法获取令牌,angular,Angular,该代码应该通过API通过电子邮件和密码登录用户,然后获取访问令牌,但它没有。在本地存储中没有令牌。当我输入错误的密码时,它会在控制台中显示错误,状态为:401,当我输入正确的密码时,它不会显示任何错误,而且在网络选项卡中,对于具有正确密码的请求,状态为200,因此我认为它会登录,但不会获取令牌 import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from

该代码应该通过API通过电子邮件和密码登录用户,然后获取访问令牌,但它没有。在本地存储中没有令牌。当我输入错误的密码时,它会在控制台中显示错误,状态为:401,当我输入正确的密码时,它不会显示任何错误,而且在网络选项卡中,对于具有正确密码的请求,状态为200,因此我认为它会登录,但不会获取令牌

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ApiService } from '../api.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login1',
  templateUrl: './login1.component.html',
  styleUrls: ['./login1.component.css']
})
export class Login1Component implements OnInit {
loggedIn = false;
loginForm: FormGroup;
  constructor(private api: ApiService, private route: Router, private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.loginForm = this.formBuilder.group({
      email: ['', Validators.required],
      password: ['', Validators.required]
    })
  }

  onSubmit() {
    const user = {
      email: this.loginForm.controls.email.value,
      password: this.loginForm.controls.password.value
    };

    this.api.loginUser(user);
    this.api.isUserLoggedIn.subscribe( (val) => {
      this.loggedIn = val;
      this.route.navigate(['/dashboard']);
    });

  }

}
服务

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  checkStatus = new BehaviorSubject<boolean>(false);
  isUserLoggedIn = this.checkStatus.asObservable();

  readonly loginUrl= 'https://*************';

  constructor(private http: HttpClient) { }

  checkLogin() {
    const token = localStorage.getItem('access_token');
    if(token) {
      this.checkStatus.next(true);
    } else {
      this.checkStatus.next(false);
    }
  }

  loginUser(user: any) {
    return this.http.post(this.loginUrl, user)
    .subscribe((checkUser: any) => {
      if(checkUser.access_token) {
        localStorage.setItem('access_token', checkUser.access_token);
        localStorage.setItem('user', JSON.stringify(checkUser.user));
        return true;
      }
    });
  }

}
从'@angular/core'导入{Injectable};
从'@angular/common/http'导入{HttpClient};
从“rxjs”导入{BehaviorSubject};
@注射的({
providedIn:'根'
})
出口级服务{
checkStatus=新行为主体(false);
isUserLoggedIn=this.checkStatus.asObservable();
readonly loginUrl='https://**************';
构造函数(私有http:HttpClient){}
checkLogin(){
const token=localStorage.getItem('access_token');
如果(令牌){
this.checkStatus.next(true);
}否则{
this.checkStatus.next(false);
}
}
登录用户(用户:任意){
返回this.http.post(this.loginUrl,用户)
.订阅((选中用户:任意)=>{
if(checkUser.access\u令牌){
localStorage.setItem('access\u token',checkUser.access\u token);
setItem('user',JSON.stringify(checkUser.user));
返回true;
}
});
}
}

你的代码看起来不错。天真的问题,您是否检查过您的API是否正确地发送回“checkUser.access_token”并且它不是未定义的

此外,本地存储不是存储身份验证令牌的推荐位置

浏览器本地存储(或会话存储)不安全。任何数据 存储在其中可能容易受到跨站点脚本攻击。如果攻击者 窃取令牌后,他们可以访问并请求您的API

通常在处理SPA时,您会在内存中使用。Cookie也是一个选项,有一些限制和注意事项。如果您使用node.js/express作为后端,我建议使用,因为它非常有助于以安全的方式设置会话访问令牌


关于商店代币,我建议这样读:

您的代码看起来不错。天真的问题,您是否检查过您的API是否正确地发送回“checkUser.access_token”并且它不是未定义的

此外,本地存储不是存储身份验证令牌的推荐位置

浏览器本地存储(或会话存储)不安全。任何数据 存储在其中可能容易受到跨站点脚本攻击。如果攻击者 窃取令牌后,他们可以访问并请求您的API

通常在处理SPA时,您会在内存中使用。Cookie也是一个选项,有一些限制和注意事项。如果您使用node.js/express作为后端,我建议使用,因为它非常有助于以安全的方式设置会话访问令牌


关于存储令牌,我建议这样读:

在尝试访问令牌之前,您必须等待loginUser

this.api.loginUser(user).subscribe(() => {
    this.api.isUserLoggedIn.subscribe( (val) => {
      this.loggedIn = val;
      this.route.navigate(['/dashboard']);
    });
});
老实说,我甚至不认为订阅isUserLoggedIn有什么意义。相反,您可以使用loginUser方法中返回的值

this.api.loginUser(user).subscribe((val) => {
   this.loggedIn = val;
   if (val) {
      this.route.navigate(['/dashboard']);
   }
});

在尝试访问令牌之前,您必须等待loginUser

this.api.loginUser(user).subscribe(() => {
    this.api.isUserLoggedIn.subscribe( (val) => {
      this.loggedIn = val;
      this.route.navigate(['/dashboard']);
    });
});
老实说,我甚至不认为订阅isUserLoggedIn有什么意义。相反,您可以使用loginUser方法中返回的值

this.api.loginUser(user).subscribe((val) => {
   this.loggedIn = val;
   if (val) {
      this.route.navigate(['/dashboard']);
   }
});

我用this.loggedIn=val.valueOf()编辑了问题try强制它从
可观察的
返回原语。我使用
this.loggedIn=val.valueOf()编辑了问题try
强制它从
可观察的
返回原语。因此,也许您应该检查“if(checkUser.success.token)”并设置“localStorage.setItem('access_token',checkUser.success.token);”。我是否遗漏了什么?如果令牌存储在内存中而不是浏览器的本地存储中,那么当重新加载spa网页时会发生什么情况?内存中的数据将被清除。。。因此,用户需要再次登录?是的,这是最简单的安全方法,但肯定不是最有效的方法。这有时是一个可行的解决方案,因为根据您的构建方式,SPA实际上不需要重新加载。在构建更大的应用程序时,您可以使用会话(服务器端会话和令牌ID)或JWT(客户端身份验证),但它们比简单地将其存储在内存中更复杂。因此,也许您应该检查“if(checkUser.success.token)”并设置“localStorage.setItem('access_token',checkUser.success.token);”。我是否遗漏了什么?如果令牌存储在内存中而不是浏览器的本地存储中,那么当重新加载spa网页时会发生什么情况?内存中的数据将被清除。。。因此,用户需要再次登录?是的,这是最简单的安全方法,但肯定不是最有效的方法。这有时是一个可行的解决方案,因为根据您的构建方式,SPA实际上不需要重新加载。在构建更大的应用程序时,您可以使用会话(服务器端会话和令牌ID)或JWT(客户端身份验证),但它们比简单地将其存储在内存中更复杂。