【问题标题】:Passing Oauth token data from service to component - Angular将 Oauth 令牌数据从服务传递到组件 - Angular
【发布时间】:2018-11-01 00:05:08
【问题描述】:

我试图弄清楚如何将作为服务中 oauth2 隐式过程的一部分返回的用户令牌传递给作为回调 url 的组件,这样我就可以在文章中进一步使用该令牌。

服务代码

import { Injectable } from '@angular/core';
import {UserManager, UserManagerSettings, User} from 'oidc-client';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
    private manager: UserManager = new UserManager(getClientSettings());
    private user: User = null;

  constructor() {
    this.manager.getUser().then(user => {
      this.user = user;
    });
  }

  isLoggedIn(): boolean {
    return this.user != null && !this.user.expired;
    }

  getClaims(): any {
  return this.user.profile;
    }

  getAuthorizationHeaderValue(): string {
      return `${this.user.token_type} ${this.user.access_token}`;
    }

  startAuthentication(): Promise<void> {
      return this.manager.signinRedirect();
    }

  completeAuthentication(): Promise<void> {
      return this.manager.signinRedirectCallback().then(user => {
        console.log(user.access_token);
          this.user = user;
      });
    }

}

export function getClientSettings(): UserManagerSettings {
  return {
    authority: 'https://someserver.com',
    client_id: 'clientid',
    redirect_uri: 'http://localhost:4200/auth-callback',
    post_logout_redirect_uri: 'http://localhost:4200/',
    response_type: "id_token token",
    scope: "openid read write",
    filterProtocolClaims: true,
    loadUserInfo: false,
    automaticSilentRenew: true,
    silent_redirect_uri: 'http://localhost:4200/silent-refresh.html'
  };
}

这使用 OICD Oauth 2 库

组件代码如下

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../services/auth.service';
import { Router, NavigationCancel, ActivatedRoute } from '@angular/router';
import { URLSearchParams } from '@angular/http';
import { Http, RequestOptions, Headers, Response} from '@angular/http';

@Component({
  selector: 'app-auth-callback',
  templateUrl: './auth-callback.component.html',
  styleUrls: ['./auth-callback.component.css'],
  providers: [AuthService]
})
export class AuthCallbackComponent implements OnInit {
  public accesstoken:any;

  constructor(private http: Http, private router: Router, private authService: AuthService, private route: ActivatedRoute) {

   }

  ngOnInit() {
    this.authService.completeAuthentication();
  }

}

正如您所看到的,组件在初始化时成功地从服务调用了 completeAuthentication,但是我不知道如何将 user_token 从服务传递给组件。您将在服务的 completeAuthentication 函数中看到此令牌引用,并且此时它确实成功地进行了控制台日志。目前,我要做的就是通过 auth 回调组件控制台记录该用户令牌,以显示其被正确传递。

【问题讨论】:

    标签: angular oauth-2.0


    【解决方案1】:

    只需从completeAuthentication返回令牌:

    completeAuthentication(): Promise<string> {
      return this.manager.signinRedirectCallback().then(user => {
        console.log(user.access_token);
        this.user = user;
        return user.access_token;
      });
    }
    

    在组件调用中:

    ngOnInit() {
      this.authService.completeAuthentication().then(token => {
        console.log('Token in component:', token);
      });
    }
    

    以某种更优雅和可重用的方式(以便其他组件在收到令牌后也可能获得令牌)是在服务中将令牌设置为 BehaviorSubject 并从任何地方订阅。

    要使其正常工作,请在 AuthService 中定义主题、可观察对象并进一步修改 completeAuthentication

    export class AuthService {
      private manager: UserManager = new UserManager(getClientSettings());
      private user: User = null;
      private _token = new BehaviorSubject<string>(null);
      private _user = new BehaviorSubject<User>(null);
      ...
      get user$(): Observable<User> {
        return this._user.asObservable().pipe(
          filter(val => val !== null),
          distinctUntilChanged(),
          share());
      }
    
      get token$(): Observable<string> {
        return this._token.asObservable().pipe(
          filter(val => val !== null),
          distinctUntilChanged(),
          share());
      }
    
      completeAuthentication(): Promise<string> {
        return this.manager.signinRedirectCallback().then(user => {
          console.log(user.access_token);
          this.user = user;
          this._user.next(user);
          this._token.next(user.access_token);
          return user.access_token;
        });
      }
      ....
    }
    

    _token_userBehaviorSubject,为各自的对象保存值。

    token$user$ 分别是令牌和用户的 Observable 流。如果它是null,它们被过滤(由filter 运算符)不返回任何值。例如,如果您希望收到 null 作为用户未登录的标志,只需将这些行注释掉即可。

    代码中的任何地方,假设您注入服务,只需使用 observable 获取最新值:

    constructor(private authService: AuthService) {
      this.authService.token$.subscribe(token => {
        console.log('Got my token', token);
      });
    
      this.authService.user$.subscribe(user => {
        console.log('Got my user', user);
      });
    }
    

    【讨论】:

    • 感谢您的帮助,看起来不错,您能否快速给出 101 我将如何切换到 BehaviourSubject?
    • 希望解释如何使用 Observables 做到这一点,请参阅修改后的答案。
    • 它确实为延迟确认答案而道歉。
    猜你喜欢
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 2014-09-24
    • 2017-05-06
    • 2021-08-05
    • 1970-01-01
    • 2013-02-03
    • 2018-03-29
    相关资源
    最近更新 更多