登录 Auth0 后找不到如何获取访问令牌

Posted

技术标签:

【中文标题】登录 Auth0 后找不到如何获取访问令牌【英文标题】:Can't find how to get Access Token after login Auth0 【发布时间】:2020-03-06 02:48:04 【问题描述】:

我正在使用 Auth0 登录用户。用户第一次登录时,我收到一个包含 access_token 和 ID 令牌的 json 响应。

我想保存这个,以便我可以使用访问令牌访问我的一个 API。

我找不到调用 xxxx.auth0.com/oauth 的方法。如果我能找到该方法并将响应保存在我的 cookie 中,那就太好了。 (除非我不应该这样做)。

我也尝试过找到一种获取访问令牌的方法,但我不明白这怎么可能。我很难处理文档。

我遇到的另一个问题是用户重新登录或刷新页面时。没有给我访问令牌。我什至没有看到 xxxx.auth0.com/oauth 的网络响应。安全不是我的强项。但我希望 Auth0 可以减轻一些负担。

import  Injectable  from '@angular/core';
import createAuth0Client from '@auth0/auth0-spa-js';
import Auth0Client from '@auth0/auth0-spa-js/dist/typings/Auth0Client';
import  from, of, Observable, BehaviorSubject, combineLatest, throwError  from 'rxjs';
import  tap, catchError, concatMap, shareReplay  from 'rxjs/operators';
import  Router  from '@angular/router';

@Injectable(
  providedIn: 'root'
)
export class AuthService 
  // Create an observable of Auth0 instance of client
  auth0Client$ = (from(
    createAuth0Client(
      domain: "XXXXX.auth0.com",
      client_id: "JXXXXXXXXXXXXXXXXXXXXG",
      redirect_uri: `$window.location.origin` + `/home`
    )
  ) as Observable<Auth0Client>).pipe(
    shareReplay(1), // Every subscription receives the same shared value
    catchError(err => throwError(err))
  );
  // Define observables for SDK methods that return promises by default
  // For each Auth0 SDK method, first ensure the client instance is ready
  // concatMap: Using the client instance, call SDK method; SDK returns a promise
  // from: Convert that resulting promise into an observable
  isAuthenticated$ = this.auth0Client$.pipe(
    concatMap((client: Auth0Client) => from(client.isAuthenticated())),
    tap(res => this.loggedIn = res)
  );
  handleRedirectCallback$ = this.auth0Client$.pipe(
    concatMap((client: Auth0Client) => from(client.handleRedirectCallback())), tap(res =>  console.log(res); )
  );


  // Create subject and public observable of user profile data
  private userProfileSubject$ = new BehaviorSubject<any>(null);
  userProfile$ = this.userProfileSubject$.asObservable();
  // Create a local property for login status
  loggedIn: boolean = null;

  constructor(private router: Router)  

  // When calling, options can be passed if desired
  // https://auth0.github.io/auth0-spa-js/classes/auth0client.html#getuser
  getUser$(options?): Observable<any> 
    return this.auth0Client$.pipe(
      concatMap((client: Auth0Client) => from(client.getUser(options))),
      tap(user => 
        this.userProfileSubject$.next(user);
      )
    );
  


  localAuthSetup() 
    // This should only be called on app initialization
    // Set up local authentication streams
    const checkAuth$ = this.isAuthenticated$.pipe(
      concatMap((loggedIn: boolean) => 
        if (loggedIn) 
          // If authenticated, get user and set in app
          // NOTE: you could pass options here if needed
          return this.getUser$();
        
        // If not authenticated, return stream that emits 'false'
        return of(loggedIn);
      )
    );
    checkAuth$.subscribe();
  

  login(redirectPath: string = '') 
    // A desired redirect path can be passed to login method
    // (e.g., from a route guard)
    // Ensure Auth0 client instance exists
    this.auth0Client$.subscribe((client: Auth0Client) => 
      // Call method to log in
      client.loginWithRedirect(
        redirect_uri: `$window.location.origin` + `/home`,
        appState:  target: redirectPath 
      );
    );
  

  handleAuthCallback() 
    // Call when app reloads after user logs in with Auth0
    const params = window.location.search;
    if (params.includes('code=') && params.includes('state=')) 
      let targetRoute: string; // Path to redirect to after login processsed
      const authComplete$ = this.handleRedirectCallback$.pipe(
        // Have client, now call method to handle auth callback redirect
        tap(cbRes => 
          // Get and set target redirect route from callback results
          targetRoute = '/home';
        ),
        concatMap(() => 
          // Redirect callback complete; get user and login status
          return combineLatest([
            this.getUser$(),
            this.isAuthenticated$
          ]);
        )
      );
      // Subscribe to authentication completion observable
      // Response will be an array of user and login status
      authComplete$.subscribe(([user, loggedIn]) => 
        // Redirect to target route after callback processing
        this.router.navigate([targetRoute]);
      );
    
  

  logout() 
    // Ensure Auth0 client instance exists
    this.auth0Client$.subscribe((client: Auth0Client) => 
      // Call method to log out
      client.logout(
        client_id: "JxxxxxxxxxxxxxxxxxxxxxxG",
        returnTo: `$window.location.origin`
      );
    );
  

如果我订阅 auth0client,我可以看到令牌。但我无法访问它以缓存私有。

  console.log(data.cache.cache["default::openid profile email"])

【问题讨论】:

【参考方案1】:

我有同样的问题。而且我同意人们在通过 Auth0 SPA sdk 获得思想时会感到迷茫,因为没有明确的属性或功能来获取访问令牌。

您可以通过调用 Auth0Client 的 getTokenSilently() 方法获取访问令牌。

为了最简单的方法,可以在 Auth 服务中添加以下方法来设置访问令牌,并且可以在登录后立即调用此方法。 (这可能不是一个好主意,但会帮助您理解流程。)

setAccessToken() 
  this.auth0Client$.subscribe(async (client: Auth0Client) => 
    this.AccessToken = await client.getTokenSilently(););   

您也可以在 authService 中添加 observable 方法并从任何地方调用这个 observable(例如 http 拦截器在调用 api 的标头中添加访问令牌)

getTokenSilently$(options?): Observable<string> 
   return this.auth0Client$.pipe(
   concatMap((client: Auth0Client) => from(client.getTokenSilently(options))));

我发现获取访问令牌并将其与 http 拦截器一起使用以将其添加到 http 调用的标头的最佳示例之一是 enter link description here

【讨论】:

老实说,我正在做的是使用钩子。因此,在用户注册后,auth0 会向用户发送 authid 和电子邮件,并将其存储到我的数据库中。 Auth0 必须发送一个密钥,以排除机器人或其他任何不是 Auth0 的人。然后,如果用户想要执行 CRUD 操作,他们会发送电子邮件和 authID,我会对其进行验证。

以上是关于登录 Auth0 后找不到如何获取访问令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何在附加 API 服务 Auth0 中获取访问令牌?

从 API 中访问 Auth0 登录用户?

如何从 django-oauth-toolkit 令牌获取当前登录用户?

如何安全地保存从 auth0 登录收到的 JWT 令牌(nodejs express)

Auth0 Laravel 获取 JWT 令牌

如何使用我的后端中使用的前端反应中的 Auth0 访问令牌