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

时间:2020-07-30 18:36:10

标签: angular typescript post single-sign-on angular8

在我的代码中,我正在实现SSO登录。我有auth.service,它在app.module.ts的app initializer内部给出。我有代码流,可以访问该服务,并在url中获取代码。现在,我想发送一个带有body的发布请求,该请求将返回访问令牌。但是,一旦发出发布请求,应用程序将刷新并重新开始该过程。尝试多次并说出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时,我应该能够获得访问令牌。但它会再次刷新该应用程序。该如何解决?

2 个答案:

答案 0 :(得分:0)

编辑1: 您是否忘记了从getAuthToken()方法内部“返回”承诺? 对我来说,您好像正在调用getAuthToken,但获得null。

编辑2: 我看不到http.post有任何东西可以导致应用刷新。 唯一会导致重新加载的内容是此行

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

我觉得问题在于这里是否满足条件:

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文档以了解期望的内容。对于用户定义的标头,应为HttpHeaders类型,并且应为对象内部具有“ headers”属性的http.post()的第三个参数。默认情况下,http客户端会为您设置一些标题。

有关其工作方式,http.post返回一个可观察的对象,您可以订阅该对象。在您的情况下,您正在遵守可观察的承诺并进一步处理它。 哪种类型的可观测?如果您要问的话,这取决于Api发送的实际响应。它可以是可观察到的字符串(可观察到的),可观察到的Blob或可观察到的具有完整http响应(Observable )等的任何内容。http.post有15种不同的重载。您指定要如何读取响应。您可以在创建请求时在http.post中设置responseType,也可以使用泛型和类型转换。 Check the documentation for clarity.

答案 1 :(得分:0)

有很多事情在您的代码中不起作用。对于if语句的每一端,您应该返回一些内容。否则可能会卡住。另外,有时您需要返回一个if语句来防止嵌套,通过这样做,您的代码(在大多数情况下)将更易于阅读

您的服务代码将如下所示:

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