0Ne*_*eji 6 .net c# umbraco azure-active-directory openid-connect
我正在使用 Azure Active Directory 向运行 Umbraco 版本 11.0 的网站上的 Backoffice 提供身份验证。
这运行良好,我可以登录,但我想通过使用 Azure 中的应用程序角色来管理 Umbraco 中的用户组来改善体验。
我的 Azure 设置
我已使用以下配置在 Azure 中创建了应用程序注册:
Access tokens (used for implicit flows)
ID tokens (used for implicit and hybrid flows)
Accounts in this organizational directory only (Example only - Single tenant)
在企业应用程序中,我还将上面的应用程序角色添加到我的用户:
我的代码
登录提供商
namespace Example.Api.Features.Authentication.Extensions;
public static class UmbracoBuilderExtensions
{
public static IUmbracoBuilder ConfigureAuthentication(this IUmbracoBuilder builder)
{
builder.Services.ConfigureOptions<OpenIdConnectBackOfficeExternalLoginProviderOptions>();
builder.AddBackOfficeExternalLogins(logins =>
{
const string schema = MicrosoftAccountDefaults.AuthenticationScheme;
logins.AddBackOfficeLogin(
backOfficeAuthenticationBuilder =>
{
backOfficeAuthenticationBuilder.AddMicrosoftAccount(
// the scheme must be set with this method to work for the back office
backOfficeAuthenticationBuilder.SchemeForBackOffice(OpenIdConnectBackOfficeExternalLoginProviderOptions.SchemeName) ?? string.Empty,
options =>
{
//By default this is '/signin-microsoft' but it needs to be changed to this
options.CallbackPath = "/umbraco-signin-microsoft/";
//Obtained from the AZURE AD B2C WEB APP
options.ClientId = "CLIENT_ID";
//Obtained from the AZURE AD B2C WEB APP
options.ClientSecret = "CLIENT_SECRET";
options.TokenEndpoint = $"https://login.microsoftonline.com/TENANT/oauth2/v2.0/token";
options.AuthorizationEndpoint = $"https://login.microsoftonline.com/TENANT/oauth2/v2.0/authorize";
});
});
});
return builder;
}
}
Run Code Online (Sandbox Code Playgroud)
自动关联账户
namespace Example.Api.Features.Configuration;
public class OpenIdConnectBackOfficeExternalLoginProviderOptions : IConfigureNamedOptions<BackOfficeExternalLoginProviderOptions>
{
public const string SchemeName = "OpenIdConnect";
public void Configure(string name, BackOfficeExternalLoginProviderOptions options)
{
if (name != "Umbraco." + SchemeName)
{
return;
}
Configure(options);
}
public void Configure(BackOfficeExternalLoginProviderOptions options)
{
options.AutoLinkOptions = new ExternalSignInAutoLinkOptions(
// must be true for auto-linking to be enabled
autoLinkExternalAccount: true,
// Optionally specify default user group, else
// assign in the OnAutoLinking callback
// (default is editor)
defaultUserGroups: new[] { Constants.Security.EditorGroupAlias },
// Optionally you can disable the ability to link/unlink
// manually from within the back office. Set this to false
// if you don't want the user to unlink from this external
// provider.
allowManualLinking: false
)
{
// Optional callback
OnAutoLinking = (autoLinkUser, loginInfo) =>
{
// You can customize the user before it's linked.
// i.e. Modify the user's groups based on the Claims returned
// in the externalLogin info
autoLinkUser.IsApproved = true;
},
OnExternalLogin = (user, loginInfo) =>
{
// You can customize the user before it's saved whenever they have
// logged in with the external provider.
// i.e. Sync the user's name based on the Claims returned
// in the externalLogin info
return true; //returns a boolean indicating if sign in should continue or not.
}
};
// Optionally you can disable the ability for users
// to login with a username/password. If this is set
// to true, it will disable username/password login
// even if there are other external login providers installed.
options.DenyLocalLogin = true;
// Optionally choose to automatically redirect to the
// external login provider so the user doesn't have
// to click the login button. This is
options.AutoRedirectLoginToExternalProvider = true;
}
}
Run Code Online (Sandbox Code Playgroud)
在这个文件中,我最好按照评论所说的那样做i.e. Modify the user's groups based on the Claims returned in the externalLogin info
。
也注册在我的启动文件中
services.AddUmbraco(_env, _config)
.AddBackOffice()
.AddWebsite()
.AddComposers()
.ConfigureAuthentication()
.Build();
Run Code Online (Sandbox Code Playgroud)
我尝试向应用程序授予以下权限,但没有成功:
目前的情况是,我可以很好地登录,但如果我进行调试 externalInfo
,则不会发现用户具有上述配置的Administrator
或Editor
应用程序角色。
我的直觉是,我在 Azure Active Directory 设置中遗漏了某些内容,但我尝试了几种不同的配置,但似乎无法恢复应用程序角色。
谢谢,
本
编辑 - 2023 年 2 月 15 日:
我可以看到,当我使用as到达https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
端点时,角色又回来了。它看起来像是 .NET 应用程序使用的。我已经解码了从中检索到的令牌,它不包含角色。client_credentials
grant_type
authorization_code
我想知道 .NET 应用程序上是否有某种配置允许我添加角色。
要在令牌声明中获取应用程序角色,您可以使用客户端凭据流通过授予管理员同意来生成访问令牌。
我尝试通过 Postman 在我的环境中重现相同的结果,并得到以下结果:
我注册了一个 Azure AD Web应用程序并创建了应用程序角色,如下所示:
现在,我将这些应用程序角色分配给其企业应用程序下的用户,如下所示:
在应用程序的 API 权限中添加这些应用程序角色,如下所示:
您可以在权限下看到应用程序角色Application
,如下所示:
确保授予管理员对上述权限的同意,如下所示:
生成访问令牌时,范围应该是以您的应用程序 ID URI结尾/.default
现在,我通过 Postman 使用客户端凭据流生成访问令牌,参数如下:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
client_id: <appID>
grant_type:client_credentials
scope: api://<appID>/.default
client_secret: secret
Run Code Online (Sandbox Code Playgroud)
回复:
当我在jwt.ms中解码上述令牌时,我成功获得了声明中的应用程序角色roles
,如下所示:
请注意,应用程序角色是应用程序权限,仅适用于不涉及用户交互的客户端凭据等流程。
因此,如果您使用授权代码流、用户名密码流等委托流,您将不会在令牌声明中获得应用程序角色。
更新:
您可以使用下面的C# 代码从客户端凭据流获取访问令牌,如下所示:
using Microsoft.Identity.Client;
var clientID = "bbb739ad-98a4-4566-8408-dxxxxxxxx3b";
var clientSecret = "K.k8Q~hwtxxxxxxxxxxxxxxxU";
var tenantID = "fb134080-e4d2-45f4-9562-xxxxxx";
var authority = $"https://login.microsoftonline.com/{tenantID}";
var clientApplication = ConfidentialClientApplicationBuilder.Create(clientID)
.WithClientSecret(clientSecret)
.WithAuthority(authority)
.Build();
var scopes = new string[] { "api://bbb739ad-98a4-4566-8408-xxxxxx/.default" };
var authenticationResult = await clientApplication.AcquireTokenForClient(scopes)
.ExecuteAsync()
.ConfigureAwait(false);
var accesstoken = authenticationResult.AccessToken;
Console.WriteLine(accesstoken);
Run Code Online (Sandbox Code Playgroud)
回复:
当我解码上述令牌时,它具有应用程序角色的roles
声明,如下所示:
为了解决这个问题,我最终将 换成AddMicrosoftAccount
AuthenticationBuilder
了AddOpenIdConnect
. 这似乎尊重代币中的声明。
这是我现在在该方法中使用的代码ConfigureAuthentication
。
public static IUmbracoBuilder ConfigureAuthentication(this IUmbracoBuilder builder)
{
// Register OpenIdConnectBackOfficeExternalLoginProviderOptions here rather than require it in startup
builder.Services.ConfigureOptions<OpenIdConnectBackOfficeExternalLoginProviderOptions>();
builder.AddBackOfficeExternalLogins(logins =>
{
logins.AddBackOfficeLogin(
backOfficeAuthenticationBuilder =>
{
backOfficeAuthenticationBuilder.AddOpenIdConnect(
// The scheme must be set with this method to work for the back office
backOfficeAuthenticationBuilder.SchemeForBackOffice(OpenIdConnectBackOfficeExternalLoginProviderOptions.SchemeName),
options =>
{
options.CallbackPath = "/umbraco-signin-microsoft/";
// use cookies
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// pass configured options along
options.Authority = "https://login.microsoftonline.com/{tenantId}/v2.0";
options.ClientId = "{clientId}";
options.ClientSecret = "{clientSecret}";
// Use the authorization code flow
options.ResponseType = OpenIdConnectResponseType.Code;
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
// map claims
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
options.RequireHttpsMetadata = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.UsePkce = true;
options.Scope.Add("email");
});
});
});
return builder;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2573 次 |
最近记录: |