MSAL.Net 没有帐户或登录提示传递到 AcquireTokenSilent 调用

2024-05-08

我见过很多相同或类似的问题,并尝试了他们所有的答案(如果有的话),但这些都不适合我。

我在用着这个例子 https://github.com/Azure-Samples/ms-identity-javascript-angular-spa-aspnetcore-webapi来自微软的Github帐户作为我的项目库。

它非常适合仅登录的用户。

该项目有 1 个 WebApi、1 个 Angular App。

然后我按照这个微软的例子 https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-1-Call-MSGraph添加调用 Graph API 的代码。 这是控制器代码:

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class BillsController : ControllerBase
{
    static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };
    readonly ITokenAcquisition tokenAcquisition;
    readonly WebOptions webOptions;

    public BillsController(ITokenAcquisition tokenAcquisition,
                          IOptions<WebOptions> webOptionValue)
    {
        this.tokenAcquisition = tokenAcquisition;
        this.webOptions = webOptionValue.Value;
    }

    [HttpGet]
    [AuthorizeForScopes(Scopes = new[] { Constants.ScopeUserRead, Constants.ScopeMailRead })]
    public async Task<IActionResult> Profile()
    {
        HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);

        var subject = string.Empty;
        try
        {
            // Initialize the GraphServiceClient. 
            Graph::GraphServiceClient graphClient = GetGraphServiceClient(new[] { Constants.ScopeUserRead, Constants.ScopeMailRead });

            var me = await graphClient.Me.Request().GetAsync();
            // Get user photo
            var messages = await graphClient.Me.MailFolders.Inbox.Messages.Request().GetAsync();
            subject = messages.First().Subject;
            return Ok(subject);
        }
        catch (System.Exception ex)
        {
            throw ex;
        }
    }

    private Graph::GraphServiceClient GetGraphServiceClient(string[] scopes)
    {
        return GraphServiceClientFactory.GetAuthenticatedGraphClient(async () =>
        {
            string result = await tokenAcquisition.GetAccessTokenForUserAsync(scopes);
            return result;
        }, webOptions.GraphApiUrl);
    }
}

对于 Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        // Setting configuration for protected web api
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddProtectedWebApi(Configuration);

        services.AddWebAppCallsProtectedWebApi(Configuration, new string[] { Constants.ScopeUserRead, Constants.ScopeMailRead })
            .AddInMemoryTokenCaches();

        services.AddOptions();
        services.AddGraphService(Configuration);

        // Creating policies that wraps the authorization requirements
        services.AddAuthorization();

        services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList"));

        services.AddControllers();

        // Allowing CORS for all domains and methods for the purpose of sample
        services.AddCors(o => o.AddPolicy("default", builder =>
        {
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader();
        }));
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            // Since IdentityModel version 5.2.1 (or since Microsoft.AspNetCore.Authentication.JwtBearer version 2.2.0),
            // Personal Identifiable Information is not written to the logs by default, to be compliant with GDPR.
            // For debugging/development purposes, one can enable additional detail in exceptions by setting IdentityModelEventSource.ShowPII to true.
            // Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
            app.UseDeveloperExceptionPage();
        }
        else
        {
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseExceptionHandler("/error");

        app.UseCors("default");
        app.UseHttpsRedirection();
        app.UseCookiePolicy();
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }

在 Angular 应用程序上,我添加了一个按钮来调用此 Profile() 控制器操作。

todo-view.component.ts

  getEmails(): void {
    this.service.getEmails().subscribe({
      next: (emails: any) => {
        alert(emails);
      },
      error: (err: any) => {
        console.log("error happened~!");
        console.log(err);
      }
    });
  }

todo-view.component.html

<button (click)="getEmails();">Get Emails</button>

我将以下代码添加到 Startup.cs 中并删除了 AddWebAppCallsProtectedWebApi。 services.AddProtectedWebApiCallsProtectedWebApi(配置).AddInMemoryTokenCaches();

现在它向我抛出了不同的错误消息:


我在使用 React 应用程序时遇到了同样的问题。由于 AuthorizeForScopes 用于返回视图,因此它不适用于 API 解决方案。我能够添加一些配置选项以使其正常工作。

我做的第一件事就是使用 SQL 缓存。这有助于在站点重新启动时阻止“无登录提示”错误。之后,令牌将正常工作,直到超时,之后令牌将从缓存中删除,并且错误将再次出现。

为此,我开始查看配置设置。我将配置更改为以下内容。

services
    .AddWebAppCallsProtectedWebApi(new string[] { "User.Read" }, idOps =>
    {
        Configuration.Bind("AzureAd", idOps);
        idOps.SaveTokens = true;
        idOps.RefreshOnIssuerKeyNotFound = true;
        idOps.SingletonTokenAcquisition = true;
        idOps.UseTokenLifetime = true;
    },
    ops => Configuration.Bind("AzureAd", ops))
    .AddDistributedTokenCaches()
    .AddDistributedSqlServerCache(options =>
    {
        options.ConnectionString = Configuration.GetConnectionString("Site_DbContext");
        options.SchemaName = "dbo";
        options.TableName = "_TokenCache";
    });

我还没有对它进行太多测试来找出神奇的组合,但最佳点似乎是SingletonTokenAcquisition。有了这个集合,它的行为似乎就像一个混合缓存。首次设置时,它将令牌拉入内存并保存它,因此,如果将其从数据库缓存中删除,它仍然可以访问它。

其他设置可能是刷新所必需的,但我还没有测试过。

我注意到的一件事是,令牌在刷新之前不会被添加回 SQL 缓存,因此,如果发生令牌被删除并且站点出现故障清除内存的情况,错误可能会再次出现,但这是最好的到目前为止我找到的解决方案。我的 SPA 能够运行 24 小时,并且仍然能够提取新数据。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MSAL.Net 没有帐户或登录提示传递到 AcquireTokenSilent 调用 的相关文章

  • Android - 保留或删除应用程序卸载时创建的文件

    我创建了一个应用程序 用于创建文件并将其存储到 SD 卡 有没有办法将文件夹与应用程序绑定 以便当用户在 Android 设备上运行卸载时删除所有文件 自 2009 年以来似乎有了一些进展 来自文档 http developer andro
  • 是否可以“保护”属性并将其从选择语句中排除

    我想保护数据层级别的某些属性 例如 我想保护用户存储在数据库中的密码哈希 以便它不会以任意形式显示select 声明 仅当在 a 中明确请求时才采用这种方式select property property2陈述 我认为更准确的答案是设置se
  • 尝试在节点 0.12 上重新安装 `node-sass`?

    我想使用谷歌网络入门套件 我安装了node js v0 12 0 node sass gulp 然后跑 sudo npm install 当我打字时gulp serve然后得到这个错误 Using gulpfile web starter
  • 将静态库合并为单个

    如何将静态库合并为一个 我确实有三个静态库 libSignatureLibary armv6 a libSignatureLibary armv7 a 和 libSignatureLibary i368 a 现在我想将这三个文件合并到一个库
  • 在何处将 CFLAG(例如 -std=gnu99)添加到 (Eclipse CDT) 自动工具项目中

    我有一个简单的 Autotools C 项目 不是 C 其框架是由 Eclipse CDT Juno 为我创建的 CFLAG 通过检查 似乎是 g O2 我希望所有生成的 make 文件也具有 std gnu99附加到 CFLAG 因为我使
  • 检查php中位字段是否打开的正确方法是什么

    检查位字段是否打开的正确方法是什么 在 php 中 我想检查来自 db mysql 的位字段是否打开 这是正确的方法吗 if bit 1 还有其他方法吗 我看到有人使用代码ord http jameslow com 2008 08 12 m
  • 通过 cmake 链接作为外部项目包含的 opencv 库[重复]

    这个问题在这里已经有答案了 我对 cmake 比较陌生 经过几天的努力无法弄清楚以下事情 我有一个依赖于 opencv 的项目 它本身就是一个 cmake 项目 我想静态链接 opencv 库 我正在做的是我的项目中有一份 opencv 源
  • 如何处理两个 gradle 插件的任务冲突?

    我使用 gradle 和两个插件com jfrog artifactory and io swagger core v3 swagger gradle plugin 现在我想按照此处所述进行配置https github com swagge
  • 创建带有部分的选项卡式侧边栏 WPF

    我正在尝试创建一个带有部分的选项卡式侧边栏 如 WPF 中的以下内容 我考虑过几种方法 但是有没有更简单 更优雅的方法呢 方法一 列表框 Using a ListBox并将 SelectedItem 绑定到右侧内容控件所绑定的值 为了区分标
  • 我找不到 IntelliJ 快捷方式

    我使用 vim 一段时间 我知道有一个 intellij vim 插件 我很好奇内置的 IntelliJ 文本导航存在什么 如何打开实时模板来创建模板 如何查看以 tr 开头的现有模板列表 如何进行全局搜索并在当前文档中进行搜索 然后转到下
  • 将文本从文本文件添加到 PDF 文件[重复]

    这个问题在这里已经有答案了 这是我的代码 using FileStream msReport new FileStream pdfPath FileMode Create step 1 using Document pdfDoc new D
  • 使用剪贴板 SetText 换行

    如何使用 SetText 方法添加换行符 I tried Clipboard SetText eee n xxxx 但当我将剪贴板数据粘贴到记事本中时 它没有给我预期的结果 预期结果 eee xxxx 我怎样才能做到这一点 Windows
  • 添加两个 ActiveRecord::Relation 对象[重复]

    这个问题在这里已经有答案了 如何将两个关系添加在一起 当我尝试 运算符时 它返回一个数组 但我需要它来返回关系 谢谢 麦克风 Try new relation relation merge another relation
  • 如何从函数返回矩阵(二维数组)? (C)

    我创建了一个生成宾果板的函数 我想返回宾果板 正如我没想到的那样 它不起作用 这是函数 int generateBoard int board N M i j fillNum Boolean exists True initilize se
  • Tensorflow Eager Execution 不适用于学习率衰减

    在这里尝试让一个热切的执行模型与 LR 衰减一起工作 但没有成功 这似乎是一个错误 因为学习率衰减张量似乎没有更新 如果我遗漏了什么 你可以帮我一下吗 谢谢 下面的代码正在学习一些词嵌入 但是 那学习率衰减部分根本不起作用 class Wo
  • 如何确定给定方法可以抛出哪些异常?

    我的问题和这个真的一样 找出 C 中方法可能抛出的异常 https stackoverflow com questions 264747 finding out what exceptions a method might throw in
  • 如何过滤 Solr 中多值字段返回的值

    我有一个文档 其中包含一个名为 uuid 的字段 该字段是一个列表 多值 每个文档最多可以有 100k 个值 例如 我想搜索与以 5ff6115e 开头的 uuid 匹配的文档 我已经可以通过使用成功做到这一点q uuids 5ff6115
  • 使用 JQuery 预填充选择字段的下拉选项验证

    我有这个 JQuery 片段来防止选择已在另一个字段中选择的下拉选项 var coll select name service on change function coll each function var val this value
  • 搜索引擎如何找到相关内容? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 Google 在解析网络时如何找到相关内容 例如 Google 使用 PHP 原生 DOM 库来解析内
  • 如何从 TraCIDem11p.cc 获取 RSU 坐标?

    我想知道如何开始编写一个能够在车辆靠近 RSU 时发送消息的程序 首先 我仍然对一些定义感到困惑 但是 一点一点地 我想我会学习静脉 module simulation getModuleByPath rsu 0 c MobilityAcc

随机推荐