axios 如何在混合ASP.NET核心MVC(后端)和Vuejs SPA(前端)中配置Azure AD身份验证?

uyto3xhc  于 2022-12-29  发布在  iOS
关注(0)|答案(1)|浏览(263)

我的应用程序是一个混合的方法,其中使用ASP.NET核心MVC作为我的后端。我有各种各样的控制器,我的前端用来从我们的数据库拉数据,也做API调用MS图。我使用以下program.cs文件,以获得身份验证时,用户首次登录到网站:

//authentication pipline
builder.Services.AddHttpContextAccessor();
var initialScopes = builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApp(options =>
                {
                    builder.Configuration.Bind("AzureAd", options);
                    options.Events = new OpenIdConnectEvents
                    {
                        //Tap into this event to add a UserID Claim to a new HttpContext identity
                        OnTokenValidated = context =>
                        {
                            //This query returns the UserID from the DB by sending the email address in the claim from Azure AD
                            string query = "select dbo.A2F_0013_ReturnUserIDForEmail(@Email) as UserID";
                            string connectionString = builder.Configuration.GetValue<string>("ConnectionStrings:DBContext");
                            string signInEmailAddress = context.Principal.FindFirstValue("preferred_username");

                            using (var connection = new SqlConnection(connectionString))
                            {
                                var queryResult = connection.QueryFirst(query, new { Email = signInEmailAddress });

                                var claims = new List<Claim>
                                {
                                    new Claim("UserID", queryResult.UserID.ToString())
                                };

                                var appIdentity = new ClaimsIdentity(claims);

                                context.Principal.AddIdentity(appIdentity);
                            }

                            return Task.CompletedTask;
                        },
                    };
                }).EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
                        .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
                        .AddInMemoryTokenCaches();

//Add Transient Services
builder.Services.AddTransient<IOneDrive, OneDrive>();

builder.Services.AddControllers(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();

builder.Services.AddRazorPages().AddRazorPagesOptions(options =>
{
    options.Conventions.AllowAnonymousToFolder("/Login");
    options.Conventions.AuthorizeFolder("/");
    options.Conventions.AuthorizeFolder("/files");
}).AddMicrosoftIdentityUI();

// Add the UI support to handle claims challenges
builder.Services.AddServerSideBlazor()
   .AddMicrosoftIdentityConsentHandler();
builder.Services.AddRequiredScopeAuthorization();

在Azure AD门户中,我的应用程序被注册为Web应用程序。因此,当用户最初访问该站点时,他们将被重定向到https://login.microsoftonline.com/blahblah以启动登录过程。这是由Azure AD身份平台自动执行的。然后,一旦登录,他们将被重定向到加载VueJS spa的localhost(localhost:43862)。我的spa使用各种axios请求来访问控制器,它们将提取数据并加载vue路由器组件。但是,我的问题是,用户需要重新登录,因为cookie已过期或他们在另一个选项卡中注销。过期会话发出的下一个axios请求不会将用户重定向到Azure登录屏幕,而是导致CORS错误。因此,我需要获取axios请求,以强制将页面重定向到Azure AD登录屏幕(这可能是最糟糕的主意,因为CORS策略导致错误),或者让它返回重定向到localhost/login,这是我自己的自定义登录屏幕,其中有一个Azure AD登录按钮,不应影响CORS。那么,我如何拦截此重定向到Azure AD登录
我也尝试过返回一个401错误代码,这样我就可以在我的axios请求中检查这个错误代码,但是没有任何效果。如果我在那里放置一个断点,它确实会命中这个代码,但是它不会改变响应的状态代码,我仍然得到302。我的代码是尝试添加到事件中:

OnRedirectToIdentityProvider = context =>
                    {
                        context.Response.StatusCode = 401;
                        return Task.CompletedTask;
                    }

My other ideas was maybe I should set my CORS policy to allow redirects from login.microsoft.com? Or would this be bad practice?

0ve6wy6x

0ve6wy6x1#

我可以回答您的部分问题...首先,对于受Azure AD保护的API应用程序,API应该做的是验证请求是否在请求标头中包含正确的访问令牌,如果是,则给予响应,如果否,则给出类似401或403的错误。正常的API应用程序不应该有用户登录的UI。无论如何,如果您希望在MVC项目中公开API,这是可以,但是对于API本身,它不应该有UI。
让我们看看下面的示例,我有一个.net 6 web API项目,下面是我的program.cs

using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration);
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

而且它需要在appsetting.json中进行配置。

"AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": "azure_ad_client_id",
    "ClientSecret": "client_secret",
    "Domain": "tenant_id",
    "TenantId": "tenant_id",
    //"Audience": "api://azure_ad_client_id_which exposed_api" // here I used the same azure ad app to expose API, so I can comment this property
  },

这是控制器:

[ApiController]
    [Route("[controller]")]
    [Authorize]
    public class WeatherForecastController : ControllerBase
    {
        [RequiredScope("Tiny.Read")]
        [HttpGet]
        public string Get()
        {
            return "world";
        }
    }

我有一个Azure AD应用程序,我公开了一个API,如下所示:

我还为同一Azure AD应用添加了此API。

那么我们做一个测试,当我直接调用这个API的时候,会得到401错误:

如果我在请求中使用了过期的令牌,我也会得到401错误:

但如果我使用了正确的令牌(转到https://jwt.io来解码令牌,我们应该看到它包含正确的作用域,对我来说是"scp": "Tiny.Read",),我将得到响应:

到目前为止,API部分已经完成。让我们看看客户端SPA。对于SPA,您应该集成MSAL,以便您可以让您的用户通过Azure AD登录,并生成访问令牌以调用MS图形API或您自己的API。生成访问令牌的代码应该相同,但您应该为不同的API设置不同的scope。在我的场景中,我的API需要一个作用域Tiny.Read,那么我应该在我的客户端应用程序中设置。
这是generating access token in react的屏幕截图,你需要在代码中设置作用域。

现在你已经有了生成访问令牌的方法,你已经知道了API的url。然后你可以发送请求来调用API,使用 AJAX ,使用fetch,或者其他什么,发送http请求是可以的。而且在调用API部分,你还需要处理响应。如果响应代码是401,那么你需要做一些逻辑,也许会转到登录页面。你说你在这里遇到了麻烦,您遇到了CORS问题。我无法回答此部分。我认为这取决于您如何重定向到Azure AD登录页面。我'恐怕你可以看一下this sample来学习如何登录用户和调用图API。

相关问题