Angular Auth 0 和 Azure AD 的拦截器正在干扰彼此的身份验证过程

Angular Interceptor of Auth 0 and Azure AD are interfering in each other's authentication process

我正在开发一个包含 Auth 0 和 Azure AD 的应用程序,用于不同域的用户身份验证。例如。 gmail.com 和 outlook.com 的 Auth0 以及其他域的 Azure AD。我想让它们分开。为此,我显示了一个选项页面,用户可以在其中选择登录选项(Auth0 或 AzureAd)。

我正在使用 Angularjs 框架和 .Net

如果仅使用一个登录选项(即 Auth0 或 Azure Ad)专门实施,则 Auth0 和 Azure AD 的登录过程工作顺利。但是当一起使用时它会变得乱码。问题始于状态路由和从 ClaimsPrincipal(.NET) 访问登录用户的电子邮件。一个 (Auth0/AzureAd) 似乎覆盖了 ClaimsPrincipal。例如。如果我在 Azure AD 中使用 a@b.com 登录并 post 注销,我会尝试通过 Auth0 使用电子邮件 c@[=50= 再次登录]ClaimsPrincipal 仍然是 returns Azure AD 用户的电子邮件,即 a@b 而不是 c@d。

我确信这是因为有两个拦截器拦截请求,每个拦截器一个。 ProtectedResourceInterceptor:Azure ADjwt拦截器:Auth0

我试图创建一个服务提供者,它在选择登录选项 (Auth0/AzureAD) 时动态地尝试从 $httpProvider 推送或弹出拦截器。

 app.config(['$provide', '$httpProvider', function ($provide, $httpProvider) {
    $provide.decorator('$interceptorManager', ['$delegate', '$injector', function ($delegate, $injector) {
        $delegate.addInterceptor = function (loginOptionValue) {                            
            if (loginOptionValue) {
                switch (loginOptionValue) {
                    case 'Auth 0':
                        var index = $httpProvider.interceptors.indexOf('ProtectedResourceInterceptor');
                        if (index != -1) $httpProvider.interceptors.splice(index, 1);
                        $httpProvider.interceptors.push('jwtInterceptor');
                        break;
                    case 'Azure Ad':
                        var index = $httpProvider.interceptors.indexOf('jwtInterceptor');
                        if (index != -1) $httpProvider.interceptors.splice(index, 1);
                        $httpProvider.interceptors.push('ProtectedResourceInterceptor');
                        break;
                }
            }
            console.log('Adding Interceptio: '+$httpProvider.interceptors.length);
        }
        $delegate.removeInterceptors = function (loginOptionValue) {
            var index = -1;
           //var index = $httpProvider.interceptors.indexOf('ProtectedResourceInterceptor');
           //if (index != -1) $httpProvider.interceptors.splice(index, 1);

           index = $httpProvider.interceptors.indexOf('jwtInterceptor');
           if (index != -1) $httpProvider.interceptors.splice(index, 1);
        }
        $delegate.printInterceptors = function () {
            for (var i = 0 ; i < $httpProvider.interceptors.length ; i++)
                console.log($httpProvider.interceptors[i]);
        }
        return $delegate;
    }]);
}]);

但是 似乎对我不起作用。我应该如何在同时部署 Auth 0 和 Azure AD 的同时实现不间断的登录过程

放弃了 从 Auth0 访问 Azure Ad 的想法。我回滚到之前的步骤,在那里我可以选择两者(Auth0 或 Azure AD)。

对于任何正在寻找答案的人,好吧,我尝试编辑拦截器。我不知道我是否应该编辑拦截器,但我做了很少的事情并且对我来说很有效。

就这样吧。我创建了一个 angular value 并在 module creation 开始时将其命名为 loginOption 和 属性 valueloginOption 可以将 Auth 0Azure AD 作为值。

app.value('loginOption', {value: null});

loginOption.value 在用户选择登录选项时填充。

对于 Auth 0 我编辑了文件 auth0-angular.js。我在 authUtilsProviderthis.$get 中注入了 loginOption 并调节了 $stateChangeStart

$rootScope.$on('$stateChangeStart', function (e, to) {
  if (!config.initialized) {
    return;
  }
  //prevent state change only when the state change is in the favor of Auth0 or login option is yet to be selected
  //now, it won't prevent state change when done by Azure AD
  if (to.data && to.data.requiresLogin && (!loginOption.value || loginOption.value === 'Auth 0')) {
    if (!auth.isAuthenticated && !auth.refreshTokenPromise) {
      e.preventDefault();
      $injector.get('$state').go(config.loginState);
    }
  }
});

对于 Azure AD 我编辑了文件 adal-angular.js。我在 ProtectedResourceInterceptor 中注入了 loginOption 并调节了一些代码。

//to prevent adding token of Azure Ad into header of Auth 0 requests
if (tokenStored && (loginOption.value === loginOptions.AZURE_AD)) {
    authService.info('Token is available for this url ' + config.url);
    // check endpoint mapping if provided
    config.headers.Authorization = 'Bearer ' + tokenStored;
    return config;
}

if (loginOption.value === loginOptions.AZURE_AD) {
    // delayed request to return after iframe completes
    var delayedRequest = $q.defer();
    authService.acquireToken(resource).then(function (token) {
        authService.verbose('Token is available');
        config.headers.Authorization = 'Bearer ' + token;
        delayedRequest.resolve(config);
    }, function (err) {
        config.data = err;
        delayedRequest.reject(config);
    });

    return delayedRequest.promise;
}

后端不需要做任何事情。请务必在 Startup.cs

中为 Auth0Azure Ad 添加令牌验证器
//for Azure Ad
UseWindowsAzureActiveDirectoryBearerAuthentication 

//for Auth0
UseJwtBearerAuthentication 

最后但并非最不重要的一点是索赔。对于 Auth0,可以从 ClaimTypes.Email 检索电子邮件,对于 Azure Ad,可以从 ClaimTypes.Name.

检索电子邮件
public static Claim GetClaim(string claimType)
{
    return ClaimsPrincipal.Current.FindFirst(claimType);
}

public static string GetLoggedInUserEmail()
{
    //Email comes up for Auth0
    var claimEmail = GetClaim(ClaimTypes.Email);

    //if claimEmail comes out to be null from ClaimTypes.Email then try it out for ClaimTypes.Name
    if (claimEmail == null)
        //Name comes up for Azure AD
        claimEmail = GetClaim(ClaimTypes.Name);

    var email = (claimEmail == null ? string.Empty : claimEmail.Value); //gets the email of the user
    return email;
}

我不确定这是否能解决我的问题,但这对我有用。如果我在回答时有任何错误,请纠正我。谢谢