【问题标题】:ASP.NET Core with React.js API authorization具有 React.js API 授权的 ASP.NET Core
【发布时间】:2022-11-25 06:35:08
【问题描述】:

我正在尝试使用具有 API 授权的 React.js 项目创建一个 ASP.NET Core,但很难找到有意义的文档/说明。

https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-7.0 似乎是一个很好的参考,但它使用的是实体框架,而我不是。我的目标是在没有 EF 的情况下管理用户身份验证。

dotnet new react -au Individual 创建的 React 模板提供了 AuthorizeService.jsOidcConfigurationController.cs 我在这里链接:https://gist.github.com/julesx/d3daa6ed5a7f905c984a3fedf02004c0

我的program.cs如下:

using Duende.IdentityServer.Models;
using Microsoft.AspNetCore.Authentication;

var ApiScopes = new List<ApiScope> {
    new ApiScope("api1", "My API")
};

var Clients = new List<Client> {
    new Client {
        ClientId = "client",

        // no interactive user, use the clientid/secret for authentication
        AllowedGrantTypes = GrantTypes.ClientCredentials,

        // secret for authentication
        ClientSecrets =
        {
            new Secret("secret".Sha256())
        },

        // scopes that client has access to
        AllowedScopes = { "api1" }
    }
};

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllersWithViews();

builder.Services.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddInMemoryApiScopes(ApiScopes)
    .AddInMemoryClients(Clients);

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    // 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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");

app.MapFallbackToFile("index.html");

app.Run();

在努力走到这一步之后,应用程序成功启动(开发环境)。

我从前端获取的内容如下:

export async function getKpiData(): Promise<IRawKpi[]> {

    const token = await authService.getAccessToken();

    const response = await fetch('/kpidata', {
        headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
    });

    if (response.status == 200) {
        return response.json();
    }

    return [];
}

这会导致对 OidcConfigurationController 的获取请求失败并出现以下错误: Unable to resolve service for type 'Microsoft.AspNetCore.ApiAuthorization.IdentityServer.IClientRequestParametersProvider' while attempting to activate 'MyNamespace.Controllers.OidcConfigurationController'.

我知道这是因为我没有将 IClientRequestParametersProvider 注册到 OidcConfigurationController 中,但是当我查看示例代码时,我也没有看到它被注入到那里。我也没有看到任何明显的东西我应该注入Program.csbuilder.Services

我在正确的轨道上吗?配置它所需的“神秘”知识量似乎难以承受。我可以参考某个地方的质量示例吗? Program.cs 实现一些超级基本身份验证的最低要求是什么?

【问题讨论】:

    标签: reactjs asp.net asp.net-core authentication


    【解决方案1】:

    IClient RequestParameters Provider 已注册调用

    builder.Services.AddIdentityServer()
        .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
    

    问题是默认情况下没有用户的“内存中”存储。在这种情况下,客户端是应用程序而不是用户。默认身份验证模板使用基于“MS Identity”的“IdentityServer”,而“MS Identity”本身使用 EF Core。因此,要实现此功能,您必须使用 EF Core。您可以做的是不使用 sqlserver 来拥有一个内存数据库来存储用户。

    为此,在 csproj 中将“Microsoft.EntityFrameworkCore.SqlServer”的 SqlServer PackageReference 替换为“Microsoft.EntityFrameworkCore.Sqlite”

    然后在Program.cs替换

    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(connectionString));
    

    var connection = new Microsoft.Data.Sqlite.SqliteConnection(connectionString);
    // Open the inmemory database to make sure every instance of DbContext gets the same database all the time
    connection.Open();
    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlite(connection));
    

    这可确保数据库始终相同且不会重新创建。

    在 appsettings.json 中,将 DefaultConnectionString 设置为“DataSource=:memory:”,用于基于 sqlite 的内存数据库(比实际的“InMemory”EF-Core 数据源更推荐)。

    从现在开始将在每次启动时为您提供一个干净的数据库,但会在 DbContext 的不同实例之间保持数据库打开。 现在您需要在每次启动时“播种”您想要的用户。 为此,您可以在 appsettings.json 中创建一个条目:

      "Users": {
        "test@test.com": "Password1!" 
      },
    

    然后在 var app = builder.Build(); 下的 Program.cs 中确保数据库已创建,然后遍历该用户并将它们播种到数据库中,如下所示:

    // Create a new service scope for seeding the database
    using (var scope = app.Services.CreateScope())
    {
        var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        // Make sure we create the in-memory database first
        await dbContext.Database.EnsureCreatedAsync();
        await dbContext.SaveChangesAsync();
    
        // Get the usermanager from that scope. UserManager configures MS Identity Users.
        var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
    
        // Loop over the key value pairs in the "Users" Section of the appsettings.json
        foreach (var (user, password) in app.Configuration.GetSection("Users").Get<Dictionary<string, string>>())
        {
            // Create the user and make sure the user can log in
            var result = await userManager.CreateAsync(new ApplicationUser()
            {
                UserName = user,
                EmailConfirmed = true
            }, password);
    
            // Throw if anything goes wrong (e.g. password not safe enough)
            if (!result.Succeeded) throw new Exception(string.Join(", ", result.Errors.Select(x => x.Description)));
        }
    }
    

    以下是完整 Program.cs 和 appsettings.json 的要点: https://gist.github.com/WolfspiritM/cf74430e4178cdaea94de5109413e796

    【讨论】:

      最近更新 更多