代码流身份验证 Angular 8 无法获取访问令牌

Code Flow Authentication Angular 8 unable to get access token

在我的代码中,我实现了 SSO 登录。我有 auth.service,它在 app.module.ts 中的 app initializer 中给出。我有代码流,我可以打服务,拿到url里面的代码。现在我想发送一个 post 请求,其中携带一个 body ,它将 return 访问令牌。但是一旦 post 请求被命中,应用程序就会刷新并且进程再次启动。它在多次尝试后退出循环并说 Authorization code has expired。我的代码如下: 在 app.module.ts 文件中

export function appsso(http: HttpClient, authService: AuthService) {
return (): Promise<any> => {
return authService.init()
};

 {provide: APP_INITIALIZER, useFactory: appsso, deps: [HttpClient, AuthService], multi: true}

在 authService 文件中

constructor(private http: HttpClient) {}

  init() {
    return new Promise<void>((resolve, reject) => {
    console.log('init is called');
    if (localStorage.getItem('token')) {              // if we have token, its good to go
      console.log('good to go');
      } else {
      if (!location.href.includes('?code=')){        // if url contains code
         const params = [
        'response_type=code',
        'client_id=abcde',
        'scope=openid profile',
        'redirect_uri=https://URLhere/a.0/',
        ];
        location.href = 'https://secureURLhere/authorize?' + params.join('&');      
        return 
      } else {
        const code = window.location.href.split('=')[1];     //split url to extract code
        return this.getAuthToken(code).then(data): any => {
        localStorage.setItem('tokenData', data);
        console.log('access token received');
        resolve();}, error ((err) => {
        console.log ('error occured');
        reject();
      }    
    }
  }
getAuthToken(code: string){
  let body: HttpParams = new HttpParams();
  body = body.append('grant_type', 'authorization_code')
  body = body.append('code', code)
  body = body.append('client_id', 'abcde')
  body = body.append('client_secret', '12345');
  return this.http.post('https://secureURLhere/token', body).toPromise();   //making post call
}

此外 header 的类型为 'Content-Type': 'application/x-www-form-urlencoded' 当 Post API 被命中时,我应该能够获得访问令牌。但它会再次刷新应用程序。如何解决?

编辑 1: 您是否忘记了“return”来自 getAuthToken() 方法内部的承诺? 对我来说,您似乎正在调用 getAuthToken 但得到的是空值。

编辑 2: 我没有看到任何 http.post 会导致应用程序刷新的内容。 唯一会导致重新加载的是这一行

 location.href = 'https://secureURLhere/authorize?' + params.join('&'); 

我觉得这里的 if 条件有问题:

location.href.includes('?code=')

您可能希望在设置参数时在 getAuthToken 中检查该部分。我认为您得到的是 &code= 而不是预期的 ?code= 我可能是错的。

编辑 3

查看代码,我猜这就是 POST 请求的运行方式:

POST https://secureURLhere/token HTTP1.1
(Below is body part)
grant_type=authorization_code&code=code&client_id=abcde&client_secret=12345

您可以在 chrome 开发工具的网络选项卡中查看它以进行验证。将其展示给您的 API 人员或检查 API 的文档以了解预期内容。至于用户定义的 headers,它应该是 HttpHeaders 类型,并且应该是 object 中 http.post() 的第三个参数,属性 称为“headers ”。默认情况下,http 客户端会为你设置一些 headers。

关于它的工作原理,http.post return是一个您可以订阅的可观察对象。在您的情况下,您正在将 observable 转换为承诺并进一步处理它。 什么样的可观察对象?如果你问,那么这取决于 Api 发送的实际响应。它可以是字符串的可观察对象(Observable)、Blob 的可观察对象或具有完整 http 响应的可观察对象(Observable)等。http.post 有 15 种不同的重载。您指定要如何阅读响应。您可以在创建请求时在 http.post 中设置 responseType 或使用泛型和类型转换。 Check the documentation for clarity.

有很多东西在您的代码中不起作用。对于 if 语句的每一端,你应该 return 一些东西。否则可能会卡住。此外,有时您需要在 if-statement 中 return 以防止嵌套,通过这样做您的代码将更易于阅读(大多数情况下)

您的服务代码如下所示:

import { HttpClient, HttpParams } from '@angular/common/http';

export interface AuthTokenResponse {
  access_token: string;
  id_token: string;
  expire_in: number;
  token_type: string;
}

class AuthService {
  constructor(private http: HttpClient) {}

  init() {
    return new Promise<void>((resolve, reject) => {
      // Check if token is in local storage
      if (localStorage.getItem('auth-token')) {
        // We have a token, so can continue
        return resolve();
      }

      // Create object from the URL query parameters
      const params = window.location.search
        .substr(1)
        .split('&')
        .reduce((prev, current) => {
          const [key, value] = current.split('=');
          if (key || (value !== undefined && value !== null)) {
            prev[key] = value;
          }
          return prev;
        }, {});

      // Check if the code is in the parameters
      if (params && params['code']) {
        // Code present. Use code to get Auth token
        return this.getAuthToken(params['code']).then(
          (data) => {
            // We get a access token. Save the token to the local storage
            localStorage.setItem('auth-token', JSON.stringify(data));
            resolve();
          },
          (err) => {
            // Something went wrong
            reject();
          }
        );
      }

      // No token was present in the parameters, so redirect to SSO URL
      const redirectParams = new HttpParams()
        .set('response_type', 'code')
        .set('client_id', 'abcde')
        .set('scope', 'openid profile')
        .set('redirect_uri', 'https://URLhere/a.0/');

      location.href =
        'https://secureURLhere/authorize?' + redirectParams.toString();
      return reject();
    });
  }

  getAuthToken(code: string): Promise<AuthTokenResponse> {
    // Create the body used tor the URL to get the auth token
    const body = new HttpParams()
      .append('grant_type', 'authorization_code')
      .append('code', code)
      .append('client_id', 'abcde')
      .append('client_secret', '12345');

    // Send API Post request to SSO API
    return this.http
      .post<AuthTokenResponse>('https://secureURLhere/token', body)
      .toPromise(); //making post call
  }
}