OAuth2和angular-auth2-oidc库的问题-PKCE代码流

问题描述

我是OAuth2和angular-auth2-oidc库的新手,所以如果我犯了一些新手错误,请多多包涵。

我要实现的目标:用户将单击主页上的登录链接,他将被发送到提供者的网站进行登录,然后使用令牌重定向回主页。

结果很糟糕:用户已成功发送到提供商的网站进行登录,并成功发送回我的网站主页,但我没有获得任何令牌。 我在ngOnit()的控制台中输出了一些数据,它们都是null,undefined或false。

ngOnit()函数中,我还输出一些事件,而在控制台中得到的事件是token_refresh_error。我没有明确地在代码中进行任何令牌刷新,但仍然出现此错误

在此帖子的 Error 标题下,我添加了有关错误的屏幕截图。

以下是我的配置和实现:

这是我的OAuth2提供程序的openid配置:

authorization_endpoint                  "https://DOMAIN_PROVIDER/op/v1/auth"
code_challenge_methods_supported    
    0                                   "plain"
    1                                   "S256"
end_session_endpoint                    "https://DOMAIN_PROVIDER/op/v1/logout"
grant_types_supported   
    0                                    "authorization_code"
id_token_signing_alg_values_supported   
    0                                    "RS256"
issuer                                   "https://DOMAIN_PROVIDER/op"
jwks_uri                                 "https://DOMAIN_PROVIDER/op/v1/keys"
response_modes_supported    
    0                                    "query"
    1                                    "fragment"
    2                                    "form_post"
response_types_supported    
    0                                    "code"
scopes_supported    
    0                                    "openid"
subject_types_supported 
    0                                    "public"
token_endpoint                           "https://DOMAIN_PROVIDER/op/v1/token"
token_endpoint_auth_methods_supported   
    0                                    "client_secret_basic"
    1                                    "client_secret_post"
userinfo_endpoint                        "https://DOMAIN_PROVIDER/op/v1/userinfo"

这是我的实现方式:

//主页组件

export class HomeComponent implements OnInit {

  private oAuthConfig: AuthConfig;

  constructor(private oAuthService: OAuthService) { }

   ngOnInit() {

     // IN THIS METHOD I'M OUTPUTTING ALOT OF STUFF TO THE CONSOLE TO SEE IF IT IS WORKING

      if (!this.oAuthService.getAccesstoken()) {
         this.initOAuthConfig();
         console.log('__________ACCESS-TOKEN IS NOT SET___________');
      } else {
         console.log('___ACCESS-TOKEN IS SET:',this.oAuthService.getAccesstoken());
      }

      console.log('_____GRANTED-ScopE:',this.oAuthService.getGrantedScopes());
      console.log('______IDENTITY-CLAims:',this.oAuthService.getIdentityClaims());
      console.log('______HAS-ACCESS-TOKEN?:',this.oAuthService.hasValidAccesstoken());
      console.log('_____HAS-ACCESS-TOKEN?:',this.oAuthService.hasValidIdToken());
      
    // HERE I'M OUTPUTTNG THE EVENTS TO SEE WHAT IS GOING ON
    this.oAuthService.events.subscribe((e: OAuthErrorEvent) => {
      if (e.type === 'token_received') {
        this.logger.log('____________TOKEN RECEIVED');
      }
      this.logger.log('______====================EVENT-TYPE:',e.type);
      this.logger.log('______====================EVENT-REASON:',e.reason);
      this.logger.log('______====================EVENT-ParaMS:',e.params);
    });

  
    if (this.oAuthService.hasValidAccesstoken()) {
      this.oAuthService.loadUserProfile().then((t) => {
        console.log('----USER-PROFILE:',t);
      });
    } else {
      this.logger.log('----HAS VALID ACCESS TOKEN');
    }

   }

  
   
   private initOAuthConfig(): void {
    this.oAuthConfig = {
      redirectUri: window.location.origin + '/login/oauth2/myapp',postlogoutRedirectUri: window.location.origin + '/logout',clientId: 'CLIENT-ID',scope: 'openid,rrn,profile',oidc: true,issuer: 'https://DOMAIN_PROVIDER/op',responseType: 'code',showDebuginformation: true,tokenEndpoint: 'DOMAIN_PROVIDER/op/v1/token',jwks: {'keys': ['DOMAIN_PROVIDER/op/v1/keys']}
    };

    this.oAuthService.setStorage(sessionStorage);
    this.oAuthService.configure(this.oAuthConfig);
    this.oAuthService.loaddiscoveryDocumentAndTryLogin();

}

//包含登录功能的类

export class HeaderComponent {

    
   constructor(private oAuthService: OAuthService) { }


    public login() {
     this.oAuthService.initCodeFlow();
    }

    public logout() {
      this.oAuthService.logout();
    }

}



// The html of the header component which contains the login link

    <a (click)="login()" title="Login">
       Login
    </a>

//错误/错误的屏幕截图

以下是将用户重定向回首页时控制台中的错误

1)在此屏幕快照中,值是null,false或未定义,除非加载了发现文档:

enter image description here

2)在下面的屏幕截图中,您会看到 EVENT-TYPE 之一是token_refresh_error。并且事件原因BAD REQUEST。它尝试向https//DOMAIN_PROVIDER/op/v1/token发出请求,但是失败了,尽管在de initOAuthConfig()方法中,我添加tokenEndPoint属性。 您还可以看到错误error: "invalid_grant"。 屏幕截图的第二行显示获取令牌时出错

我在{strong> initOAuthConfig()中添加jwks: {'keys': ['https://DOMAIN_PROVIDER/op/v1/keys']},以为它可以解决问题,但不能解决问题。

enter image description here

//控制台的“应用程序”选项卡:会话存储

从控制台的“应用程序”选项卡中,我可以看到会话存储中有一些键值数据对(本地存储中没有数据)请参见下一个屏幕截图:

enter image description here

解决方法

我打算分两个阶段实施您的解决方案:

  • 首先了解OAuth和Open Id Connect设计模式-希望我可以通过一个简单的TypeScript代码示例为您提供帮助
  • 考虑将样本转换为Angular的最佳方法,我相信您可以轻松完成

配置文件

我喜欢通过JSON配置表示OAuth设置-请参见this file。您可以更新文件以匹配您的配置,运行我的示例,然后希望您会看到令牌返回。

API客户端职责

当UI调用API时,它必须首先获取访问令牌,并且UI还必须处理过期的/ 401响应-请参见this class

OAUTH CLIENT责任

API客户端调用this class以获取令牌,该令牌使用OIDC客户端库来管理重定向,响应和返回令牌。

解释性博客帖子

另请参阅这些文章,旨在保持视觉和易于阅读: