【问题标题】:Refresh access_token using AcquireTokenSilent使用 AcquireTokenSilent 刷新 access_token
【发布时间】:2022-03-04 06:30:06
【问题描述】:

我有一个将 access_token 传递给下游 API 的 asp.netcore MVC 应用程序。

经过一番努力,我想出了如何使用 MSAL.Net 获取 access_token。但是访问令牌每小时都会过期,所以我不得不刷新它。所以我使用AcquireTokenSilent,它接受account作为参数。

我的 Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie(options =>
            {
                options.Events= new CookieAuthenticationEvents()
                {
                    OnValidatePrincipal = OnValidatePrincipal
                };
            })
            .AddOpenIdConnect(options =>
            {
                options.Authority = "https://login.microsoftonline.com/{tenantId}/v2.0";
                options.ClientId = Configuration["AzureAD:ClientId"];
                options.ClientSecret = Configuration["AzureAD:ClientSecret"];
                options.CallbackPath = Configuration["AzureAD:CallbackPath"];
                options.ResponseType = "code id_token";
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Scope.Add("offline_access");
                options.Scope.Add("api://{ClientidOfAPI}/user_impersonation");
                options.SaveTokens = true;
                options.Events= new OpenIdConnectEvents()
                {
                    OnAuthorizationCodeReceived = OnAuthorizationCodeReceived
                };
            });

        services.AddMvc(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 
       
    }
     

     private async Task OnValidatePrincipal(CookieValidatePrincipalContext context)
     {

         var application = GetOrBuildConfidentialClientApplication(context.HttpContext, context.Principal);
         var accounts = await application.GetAccountsAsync();
         
        AuthenticationResult result = await application.AcquireTokenSilent(
            new []{ "openid", "profile", "offline_access", "api://{ClientidOfAPI}/user_impersonation" },
            accounts.FirstOrDefault()).ExecuteAsync();
        
    }


     private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
    {
        var application = GetOrBuildConfidentialClientApplication(context.HttpContext, context.Principal);

        var result = await application.AcquireTokenByAuthorizationCode(new [] { "api://{ClientidOfAPI}/user_impersonation" }, context.ProtocolMessage.Code)
            .ExecuteAsync();

        context.HandleCodeRedemption(result.AccessToken, result.IdToken);
    }
    private IConfidentialClientApplication GetOrBuildConfidentialClientApplication(HttpContext httpContext, ClaimsPrincipal claimsPrincipal)
    {
        var request = httpContext.Request;
        string currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, "/signin-oidc" ?? string.Empty);
        string authority = $"https://login.microsoftonline.com/{tenantid}/v2.0";

        var app = ConfidentialClientApplicationBuilder.CreateWithApplicationOptions(new ConfidentialClientApplicationOptions()
            {
                ClientId = "Clientid of Client"
                ClientSecret = "password of Client"
        })
            .WithRedirectUri(currentUri)
            .WithAuthority(authority)
            .Build();
        return app;
    }

    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
           app.UseHsts();
        }
        ...

        app.UseAuthentication();

        app.UseMvc();
    }

但调用 AcquireTokenSilent 方法的 OnValidatePrincipal 无法获取账户,账户返回为空。

var accounts = await application.GetAccountsAsync();

不知道为什么我得到一个空的帐户列表。有没有更好的方法来刷新 access_token?

更新:

我稍微更改了 Startup.cs。我已经从 Startup 中删除了 OnValidatePrinciple () 并将该功能添加到 AquireTokenSilently() 到 Controller 操作。结果还是一样。

我是否需要实现缓存以从 GetAccountsAsync() 中获取价值?据我所知,我不会手动进行缓存?

【问题讨论】:

  • 您好,您找到解决方案了吗?有同样的问题。谢谢!

标签: c# asp.net-core oauth-2.0 azure-active-directory


【解决方案1】:

当您无法以静默方式获取令牌时,您需要以交互方式获取它。

根据documentation,您应该使用这样的try...catch 模式:

var accounts = await application.GetAccountsAsync();
AuthenticationResult result;
try
{
    result = await application.AcquireTokenSilent(
        new []{ "openid", "profile", "offline_access", "api://{ClientidOfAPI}/user_impersonation" },
        accounts.FirstOrDefault()).ExecuteAsync();
}
catch (MsalUiRequiredException)
{
    result = await application.AcquireTokenInteractive(
        new []{ "openid", "profile", "offline_access", "api://{ClientidOfAPI}/user_impersonation" })
        .ExecuteAsync();
}

【讨论】:

    猜你喜欢
    • 2018-01-02
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 2014-03-04
    • 2017-08-06
    • 2018-01-24
    相关资源
    最近更新 更多