如何创建API/IdentityServer/Blazor(服务器端)应用程序?

问题描述:

我尝试自己构建此应用程序,但是在此过程中遇到了几个绊脚石.我认为最好退后一步,更广泛地了解我尝试创建的内容.似乎没有任何关于如何制作所需内容的文档. (除非有人可以指出我可能错过的正确位置)

I attempted to build this application myself but, have hit several stumbling blocks along the way. I am thinking that it may be best to step back and take a larger look at what I am trying to create. There doesn't seem to be any documentation on how to make what I am looking for. (unless someone can point me in the right place I might have missed)

最终,我想让Blazor(服务器端)应用程序进行API调用以使用应用程序中的数据,然后让IdentityServer4封装身份验证.我需要具有Azure以及ASP.net Identity作为可能的身份验证方法.

Ultimately what I would like is to have a Blazor(server-side) application make API calls to use data in the app and then have an IdentityServer4 encapsulate the authentication. I need to have Azure as well as ASP.net Identity as the possible authentication methods.

我已经尝试过并且能够创建同样具有本地API的IdentityServer4.我可以打电话给邮递员来获取令牌等.但是,在将Blazor(服务器端)应用程序与IdentityServer4绑定时,我很困惑.

I have tried and was able to create an IdentityServer4 that also has a local API. I can make calls to this from Postman to get token and such. But, when it comes to tying a Blazor(server-side) application to the IdentityServer4 I am befuddled.

我试图具体询问这个问题,但是根本没有得到任何结果.我希望从更大的角度来看可能会有所帮助.

I have tried to ask this question in specifics but, haven't gotten any results at all. I am hoping maybe this larger look at it might be helpful.

似乎odic-client.js是从IdentityServer4回调中获取数据的方式,但是,这似乎与Blazor(服务器端)中的.NET授权没有很好的结合.我如何使它们一起工作.

It seems like odic-client.js is the way to get the data from the IdentityServer4 callback but, that doesn't seem to tie in nicely with the .NET Authorization in Blazor(server-side). How do I get these to work together.

重要提示:现在有比我的答案更好的消息来源了.请点击此答案最后一部分中提供的链接.

我使用API​​/IdentityServer4/Blazor(服务器端)进行了类似的设置.我将向您展示一些我使用的代码,也许您可​​以利用它.

I've got a similar setup with API / IdentityServer4 / Blazor(server-side). I'll show you some of the code I used, maybe you can make some use of it.

使用NuGet包Microsoft.AspNetCore.Authentication.OpenIdConnect,我在Startup类的ConfigureServices方法中获得了以下代码:

Using the NuGet Package Microsoft.AspNetCore.Authentication.OpenIdConnect, I've got this code in the ConfigureServices method in the Startup class:

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            options.Authority = "https://localhost:5001";

            options.ClientId = "myClient";
            options.ClientSecret = "mySecret";
            options.ResponseType = "code id_token";

            options.SaveTokens = true;
            options.GetClaimsFromUserInfoEndpoint = true;

            options.Scope.Add("MyApi");
            options.Scope.Add("offline_access");

            options.ClaimActions.MapJsonKey("website", "website");
        });

以及在Configure方法app.UseAuthentication();

and in the Configure method app.UseAuthentication();

然后在App.razor中,我使用了CascadingAuthenticationState组件:

Then in App.razor i used the CascadingAuthenticationState component:

<CascadingAuthenticationState>
     <Router AppAssembly="typeof(Startup).Assembly" />
</CascadingAuthenticationState>

在我的主页Index.razor中使用NuGet包Microsoft.AspNetCore.Authorization:

And using the NuGet package Microsoft.AspNetCore.Authorization in my main page Index.razor:

@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]

现在,当您打开主页时,它应该显示未经身份验证",但是仍然没有重定向到IdentityServer4.为此,您还必须在启动时添加MVC,正如我从

Now it should say "Not authenticated" when you open the main page but there's still no redirection to the IdentityServer4. For this you've got to add MVC in the startup too, as I learned from this * question:

        services.AddMvcCore(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        });

现在,应该在启动应用程序后将您重定向到IdentityServer4进行登录.就我而言,我有一个ApiClient,它描述了我的API的方法.我使用DI注入ApiClient并添加访问令牌:

Now you should be getting redirected to IdentityServer4 to log in after starting the application. In my case I've got an ApiClient, which describes the methods of my API. I use DI to inject the ApiClient and add the access token:

        services.AddHttpClient<IApiClient, ApiClient>(async (serviceProvider, client) =>
        {
            var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();

            var accessToken = await httpContextAccessor.HttpContext.GetTokenAsync("access_token");
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

            client.BaseAddress = new Uri("http://localhost:55578");
        });

就像您说的那样,除了关于*的一些答案以外,没有太多关于此主题的文档.我花了很长时间来设置它,所以我希望我可以在这篇文章中对其他人有所帮助.

Like you said, there is not much documentation on this topic except some answers here on *. It took me a long time to set this up, so I hope I can help someone else with this post.

更新:注销过程

使用此设置注销要绕过剃须刀页面,因为在加载blazor组件后无法访问HttpContext.

Logging out with this setup requires a detour to a razor page because the HttpContext is inaccessible after the blazor component is loaded.

在Pages文件夹中创建一个新的Razor Page,并将以下代码添加到新创建的Logout.cshtml.cs:

Create a new Razor Page in the Pages folder and add the following code to the newly created Logout.cshtml.cs:

public class LogoutModel : PageModel
{
    public async void OnGetAsync()
    {
        await HttpContext.SignOutAsync("Cookies");
        var prop = new AuthenticationProperties()
        {
            RedirectUri = "http://localhost:62909"
        };
        await HttpContext.SignOutAsync("oidc", prop);
    }
}

在某处添加一个注销按钮,该按钮依赖于@inject IUriHelper UriHelper调用函数UriHelper.NavigateTo("/Logout").完成!

Add a logout button somewhere which calls the function UriHelper.NavigateTo("/Logout") relying on @inject IUriHelper UriHelper. Done!

更新:登录解决方法

前面描述的登录过程在本地工作,但是发布到测试服务器后,我遇到了问题,在AddHttpClient方法中IHttpContextAccessor始终为null.因此,我最终使用了与注销过程相同的解决方法.我让IdentityServer重定向到一个剃刀页面(始终具有HttpContext),将访问令牌保存在用户声明中,然后重定向到索引页面.在AddHttpClient方法中,我仅从用户声明中获取令牌并将其放入身份验证标头中.

The previously described login process worked locally but after publishing to the test server, I had the problem, that the IHttpContextAccessor was always null inside the AddHttpClient method. So I ended up using the same workaround as with the logout process. I let the IdentityServer redirect to a razor page (which always has a HttpContext), save the access token in the user claim and redirect to the index page. In the AddHttpClient method I only get the token from the user claim and put it into the authentication header.

更新:未解决的问题

我仍然很难在我们的服务器上运行此设置.我打开了这个问题 https://mcguirev10.com/2019/12/15/blazor-authentication-with-openid-connect.html https://wellsb.com/csharp/aspnet/blazor-consume -identityserver4-protected-api/

I still struggle to get this setup working on our server. I opened this issue and requirement on the AspNetCore Github but both got closed without a proper answer. For the time being, I found some blogs that give a good overview of the current state of the topic: https://mcguirev10.com/2019/12/15/blazor-authentication-with-openid-connect.html https://wellsb.com/csharp/aspnet/blazor-consume-identityserver4-protected-api/