我需要构建一个.NET 7 MAUI应用程序,该应用程序在运行Duende IdentityServer(版本6.2.3)的.NET 7 ASP.NET核心应用程序上进行身份验证。我从一个概念验证应用程序开始,但在本地主机上运行IdentityServer时,我在测试它时遇到了问题。
我的代码是基于一个示例应用程序来做这件事的,可以在这里找到https://github.com/DuendeSoftware/Samples/tree/main/various/clients/Maui/MauiApp2。而IdentityServer代码几乎是一个开箱即用的IdentityServer,带有一个标准的ui,用ASP.NET核心剃刀页面代码完成。
我试过使用android模拟器进行测试,该模拟器使用ngrok生成的url调用IDP,但我得到了以下错误:
系统操作无效异常:'加载发现文档时出错:终结点与颁发机构位于不同的主机上:https://localhost:5001/. well-known/openid-configuration/jwks '
也就是说,我的权限类似于https://4cec-81-134-5-170.ngrok.io,但发现文档上的所有url仍然使用localhost url,因此不匹配。
我试过在android模拟器上测试,并使用https://10.0.2.2权威软件,但失败原因如下:
系统操作无效异常:'加载发现文档时出错:连接到https://10.0.2.2/.well-known/openid-configuration.java.security.cert时出错。证书路径验证器异常:找不到证书路径的信任锚..'
由于我只是在这里进行开发测试,所以我设置了本地IDP以使用http(而不是https),并使用http://10.0.2.2进行了测试,但失败原因如下:
系统操作无效异常:'加载发现文档时出错:连接到http://10.0.2.2/.well-known/openid-configuration时出错。需要HTTPS。'
我想知道是否有一种方法可以让我的代码通过测试localhost来工作(使用移动的应用程序或设备的模拟器).当我说我工作,我的意思是当_client.LoginAsync()
是在主页上调用上述3个错误不会发生,你会看到成功的消息.我认为这可以通过解决ngrok问题或让Android信任ASP.NET核心localhost证书或其他方法来实现https://learn.microsoft.com/en-us/dotnet/maui/data-cloud/local-web-services?view=net-maui-7.0#bypass-the-certificate-security-check。在连接到localhost时,通过将自定义HttpMessageHandler传递到httpclient来执行证书安全检查。在使用OidcClient时,是否可以执行类似的操作?
Source code for OidcClient found here
我也在https://github.com/dotnet/maui/discussions/8131这里找到了解决方案,但是我不能让4个选项中的任何一个为我工作,要么它们不支持本地主机测试,要么它们不工作。
下面是我的代码的关键部分:
IDP代码
我在Program.cs代码中添加了身份服务器,如下所示
builder.Services.AddIdentityServer(options =>
{
options.EmitStaticAudienceClaim = true;
})
.AddInMemoryIdentityResources(Config.IdentityResources)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients)
.AddTestUsers(TestUsers.Users);
下面是要引用的Config类
using Duende.IdentityServer;
using Duende.IdentityServer.Models;
namespace MyApp.IDP;
public static class Config
{
public static IEnumerable<IdentityResource> IdentityResources =>
new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
public static IEnumerable<ApiScope> ApiScopes =>
new ApiScope[]
{ };
public static IEnumerable<Client> Clients =>
new Client[]
{
new Client()
{
ClientName = My App Mobile",
ClientId = "myappmobile.client",
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = {
"myapp://callback"
},
PostLogoutRedirectUris = {
"myapp://callback"
},
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
};
}
客户端移动的代码
我像这样注册我的OidcClient
var options = new OidcClientOptions
{
Authority = "https://10.0.2.2",
ClientId = "myappmobile.client",
RedirectUri = "myapp://callback",
Browser = new MauiAuthenticationBrowser()
};
builder.Services.AddSingleton(new OidcClient(options));
MauiAuthenticationBrowser的代码如下
using IdentityModel.Client;
using IdentityModel.OidcClient.Browser;
namespace MyFirstAuth;
public class MauiAuthenticationBrowser : IdentityModel.OidcClient.Browser.IBrowser
{
public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
{
try
{
var result = await WebAuthenticator.Default.AuthenticateAsync(
new Uri(options.StartUrl),
new Uri(options.EndUrl));
var url = new RequestUrl("myapp://callback")
.Create(new Parameters(result.Properties));
return new BrowserResult
{
Response = url,
ResultType = BrowserResultType.Success
};
}
catch (TaskCanceledException)
{
return new BrowserResult
{
ResultType = BrowserResultType.UserCancel
};
}
}
}
这个应用程序只是一个带有登录按钮的页面,下面是这个页面的代码
using IdentityModel.OidcClient;
namespace MyFirstAuth;
public partial class MainPage
{
private readonly OidcClient _client;
public MainPage(OidcClient client)
{
InitializeComponent();
_client = client;
}
private async void OnLoginClicked(object sender, EventArgs e)
{
var result = await _client.LoginAsync();
if (result.IsError)
{
editor.Text = result.Error;
return;
}
editor.Text = "Success!";
}
}
1条答案
按热度按时间3xiyfsfu1#
我将创建一个新类形式的额外 Package 器,它将在里面配置您的服务。证书问题(http或https)使用Policy配置解决:
客户端移动的示例详细信息:
配置服务
使用服务
我还推荐使用secrets.json来存储设置(URI等),YouTube上有一个视频介绍如何将它们连接到Maui项目,视频名为:“.Net MAUI和Xamarin表单正在从secrets.json或appsettings.json获取设置”
最重要的是,在 Package 器中实现try-catch块会更容易
如果要将服务直接注入到页构造函数中,请不要忘记也为其指定依赖项
settings.json