You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC中访问令牌过期后无需交互登录刷新以调用Power BI API

ASP.NET MVC 无交互式登录刷新Power BI访问令牌解决方案

核心问题原因

你当前的实现存在两个核心缺失:

  • 未请求offline_access权限,无法获取刷新令牌(refresh token)
  • 仅存储了短期有效的访问令牌,未实现令牌刷新逻辑,也未利用MSAL的内置令牌缓存能力

修改步骤

1. 调整OIDC配置,请求刷新令牌所需权限

修改ConfigureAuth方法中的OpenIdConnectAuthenticationOptions配置,新增Scope配置项,添加offline_access权限和Power BI接口权限:

public void ConfigureAuth(IAppBuilder app)
{
    try
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                ClientId = clientId,
                Authority = authority,
                PostLogoutRedirectUri = postLogoutRedirectUri,
                RedirectUri = redirectUri,
                UseTokenLifetime = false,
                // 新增Scope配置
                Scope = "openid profile offline_access https://analysis.windows.net/powerbi/api/Workspace.Read.All https://analysis.windows.net/powerbi/api/Report.Read.All https://analysis.windows.net/powerbi/api/Dashboard.Read.All https://analysis.windows.net/powerbi/api/Dataset.Read.All",
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthenticationFailed = context =>
                    {
                        context.HandleResponse();
                        context.Response.Redirect("/Error?message=" + context.Exception.Message);
                        return Task.FromResult(0);
                    },
                    AuthorizationCodeReceived = OnAuthorizationCodeCallback
                }
            });

        app.UseStageMarker(PipelineStage.Authenticate);
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }
}

2. 调整授权回调逻辑,存储刷新令牌与令牌缓存关联标识

修改OnAuthorizationCodeCallback方法,除访问令牌外,额外将刷新令牌、访问令牌过期时间、MSAL用户账户标识存入用户Claims:

private static async Task OnAuthorizationCodeCallback(AuthorizationCodeReceivedNotification context)
{
    var appConfidential = ConfidentialClientApplicationBuilder.Create(clientId)
                                         .WithRedirectUri(redirectUri)
                                         .WithClientSecret(clientSecret)
                                         .WithAuthority(authority)
                                         // 配置MSAL令牌缓存,可根据需要持久化到数据库/缓存中
                                         .Build();

    string powerBiPermissionApi = "https://analysis.windows.net/powerbi/api/";
    string[] ReadUserWorkspaces = new string[] {
        powerBiPermissionApi + "Workspace.Read.All",
        powerBiPermissionApi + "Report.Read.All",
        powerBiPermissionApi + "Dashboard.Read.All",
        powerBiPermissionApi + "Dataset.Read.All"
    };

    var authResult = await appConfidential.AcquireTokenByAuthorizationCode(ReadUserWorkspaces, context.Code).ExecuteAsync();
    ClaimsIdentity userClaims = context.AuthenticationTicket.Identity;
    userClaims.AddClaim(new Claim("Access_Token", authResult.AccessToken));
    // 新增存储项
    userClaims.AddClaim(new Claim("Refresh_Token", authResult.RefreshToken));
    userClaims.AddClaim(new Claim("AccessToken_ExpiresOn", authResult.ExpiresOn.ToUnixTimeSeconds().ToString()));
    userClaims.AddClaim(new Claim("User_Account_Id", authResult.Account.HomeAccountId.Identifier));
}

3. 实现统一的有效访问令牌获取方法

新增公共方法,每次调用Power BI API前先校验令牌有效性,过期则自动用刷新令牌换取新的访问令牌:

public async Task<string> GetValidPowerBiAccessToken()
{
    var identity = (ClaimsIdentity)HttpContext.Current.User.Identity;
    // 从Claims中取出已存的令牌信息
    var existingAccessToken = identity.FindFirst("Access_Token")?.Value;
    var expiresOnUnix = long.Parse(identity.FindFirst("AccessToken_ExpiresOn")?.Value ?? "0");
    var refreshToken = identity.FindFirst("Refresh_Token")?.Value;
    var userAccountId = identity.FindFirst("User_Account_Id")?.Value;

    // 令牌未过期直接返回(提前5分钟刷新避免边界过期问题)
    if (DateTimeOffset.FromUnixTimeSeconds(expiresOnUnix) > DateTimeOffset.UtcNow.AddMinutes(5))
    {
        return existingAccessToken;
    }

    // 令牌过期,用刷新令牌换取新令牌
    var appConfidential = ConfidentialClientApplicationBuilder.Create(clientId)
                                .WithClientSecret(clientSecret)
                                .WithAuthority(authority)
                                .Build();

    string[] scopes = new string[] {
        "https://analysis.windows.net/powerbi/api/Workspace.Read.All",
        "https://analysis.windows.net/powerbi/api/Report.Read.All",
        "https://analysis.windows.net/powerbi/api/Dashboard.Read.All",
        "https://analysis.windows.net/powerbi/api/Dataset.Read.All"
    };

    AuthenticationResult authResult;
    try
    {
        // 优先用MSAL缓存静默获取
        var account = await appConfidential.GetAccountAsync(userAccountId);
        authResult = await appConfidential.AcquireTokenSilent(scopes, account).ExecuteAsync();
    }
    catch (MsalUiRequiredException)
    {
        // 缓存失效时用刷新令牌获取
        authResult = await appConfidential.AcquireTokenByRefreshToken(scopes, refreshToken).ExecuteAsync();
    }

    // 更新Claims中的令牌信息
    identity.RemoveClaim(identity.FindFirst("Access_Token"));
    identity.RemoveClaim(identity.FindFirst("AccessToken_ExpiresOn"));
    identity.RemoveClaim(identity.FindFirst("Refresh_Token"));
    identity.AddClaim(new Claim("Access_Token", authResult.AccessToken));
    identity.AddClaim(new Claim("AccessToken_ExpiresOn", authResult.ExpiresOn.ToUnixTimeSeconds().ToString()));
    identity.AddClaim(new Claim("Refresh_Token", authResult.RefreshToken));

    // 更新用户认证Cookie
    var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
    authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(
        new ClaimsPrincipal(identity),
        new AuthenticationProperties { IsPersistent = true }
    );

    return authResult.AccessToken;
}

调用说明

后续所有调用Power BI Rest API的位置,都不再直接从Claims取访问令牌,而是调用上述GetValidPowerBiAccessToken方法获取有效令牌即可,只要刷新令牌未过期,全程无需用户交互式登录。

内容的提问来源于stack exchange,提问作者PNDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 19:57:04