【发布时间】:2018-01-30 10:49:39
【问题描述】:
我最近开始使用 B2C。我设法使用 MSAL 和与我自己的租户一起工作的 API 获得了他们的 sample application/API。
现在我想:
- 了解如何在不使用 API 的情况下运行此示例。该示例使用 Scopes 获得对 API 的读/写访问权限。如果我从应用程序中删除对 API 的引用,它将不再起作用。当然应该有某种方法可以在不需要 API 的情况下对 B2C 进行身份验证?这对我的应用程序来说并不重要,但我很好奇 web 服务 HAS 是否作为身份验证过程的一部分存在?
- 与 Graph Api(Windows 或 Microsoft Graph?)通信。 sample MS 提供使用 ADAL 和一些控制台应用程序。我找不到使用 MSAL 的示例,因此无法将其合并到我自己的应用程序中。现在是否可以使用 MSAL 调用 Graph API?如果是,是否有一些关于如何在某处执行此操作的文档?
我尝试简单地按照上面的文档并注册一个应用程序/授予它权限。然后将客户端 ID/密钥放入我自己的应用程序(第一个示例中的 MSAL 应用程序),但随后我从 B2C 收到一条消息,如下所示:
相关 ID:01040e7b-846c-4f81-9a0f-ff515fd00398 时间戳:2018-01-30 10:55:37Z AADB2C90068:提供的 ID 为“9cd938c6-d3ed-4146-aee5-a661cd7d984b”的应用程序对该服务无效。请使用通过 B2C 门户创建的应用程序,然后重试。
确实没有通过B2C门户注册,但说明书上是这么说的;在应用注册下的 B2C 租户中注册,而不是在 B2c 门户中注册。
所有魔法发生的 Startup 类如下所示:
public partial class Startup
{
// App config settings
public static string ClientId = ConfigurationManager.AppSettings["ida:ClientId"];
public static string ClientSecret = ConfigurationManager.AppSettings["ida:ClientSecret"];
public static string AadInstance = ConfigurationManager.AppSettings["ida:AadInstance"];
public static string Tenant = ConfigurationManager.AppSettings["ida:Tenant"];
public static string RedirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
public static string ServiceUrl = ConfigurationManager.AppSettings["api:TaskServiceUrl"];
public static string ApiIdentifier = ConfigurationManager.AppSettings["api:ApiIdentifier"];
public static string ReadTasksScope = ApiIdentifier + ConfigurationManager.AppSettings["api:ReadScope"];
public static string WriteTasksScope = ApiIdentifier + ConfigurationManager.AppSettings["api:WriteScope"];
public static string[] Scopes = new string[] { ReadTasksScope, WriteTasksScope };
// B2C policy identifiers
public static string SignUpSignInPolicyId = ConfigurationManager.AppSettings["ida:SignUpSignInPolicyId"];
public static string EditProfilePolicyId = ConfigurationManager.AppSettings["ida:EditProfilePolicyId"];
public static string ResetPasswordPolicyId = ConfigurationManager.AppSettings["ida:ResetPasswordPolicyId"];
public static string DefaultPolicy = SignUpSignInPolicyId;
// OWIN auth middleware constants
public const string ObjectIdElement = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
// Authorities
public static string Authority = String.Format(AadInstance, Tenant, DefaultPolicy);
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
// Generate the metadata address using the tenant and policy information
MetadataAddress = String.Format(AadInstance, Tenant, DefaultPolicy),
// These are standard OpenID Connect parameters, with values pulled from web.config
ClientId = ClientId,
RedirectUri = RedirectUri,
PostLogoutRedirectUri = RedirectUri,
// Specify the callbacks for each type of notifications
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = OnRedirectToIdentityProvider,
AuthorizationCodeReceived = OnAuthorizationCodeReceived,
AuthenticationFailed = OnAuthenticationFailed,
},
// Specify the claims to validate
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
},
// Specify the scope by appending all of the scopes requested into one string (seperated by a blank space)
Scope = $"{OpenIdConnectScopes.OpenId} {ReadTasksScope} {WriteTasksScope}"
}
);
}
/*
* On each call to Azure AD B2C, check if a policy (e.g. the profile edit or password reset policy) has been specified in the OWIN context.
* If so, use that policy when making the call. Also, don't request a code (since it won't be needed).
*/
private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
var policy = notification.OwinContext.Get<string>("Policy");
if (!string.IsNullOrEmpty(policy) && !policy.Equals(DefaultPolicy))
{
notification.ProtocolMessage.Scope = OpenIdConnectScopes.OpenId;
notification.ProtocolMessage.ResponseType = OpenIdConnectResponseTypes.IdToken;
notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.ToLower().Replace(DefaultPolicy.ToLower(), policy.ToLower());
}
return Task.FromResult(0);
}
/*
* Catch any failures received by the authentication middleware and handle appropriately
*/
private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
// Handle the error code that Azure AD B2C throws when trying to reset a password from the login page
// because password reset is not supported by a "sign-up or sign-in policy"
if (notification.ProtocolMessage.ErrorDescription != null && notification.ProtocolMessage.ErrorDescription.Contains("AADB2C90118"))
{
// If the user clicked the reset password link, redirect to the reset password route
notification.Response.Redirect("/Account/ResetPassword");
}
else if (notification.Exception.Message == "access_denied")
{
notification.Response.Redirect("/");
}
else
{
notification.Response.Redirect("/Home/Error?message=" + notification.Exception.Message);
}
return Task.FromResult(0);
}
/*
* Callback function when an authorization code is received
*/
private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
{
// Extract the code from the response notification
var code = notification.Code;
string signedInUserID = notification.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
TokenCache userTokenCache = new MSALSessionCache(signedInUserID, notification.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase).GetMsalCacheInstance();
ConfidentialClientApplication cca = new ConfidentialClientApplication(ClientId, Authority, RedirectUri, new ClientCredential(ClientSecret), userTokenCache, null);
try
{
AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, Scopes);
}
catch (Exception ex)
{
//TODO: Handle
throw;
}
}
}
【问题讨论】:
标签: azure microsoft-graph-api azure-ad-b2c