我有一个ASP.Net MVC应用程序,Owin,我也使用Azure Active Directory身份验证。
我想在将用户重定向到Azure AD身份验证页面时传递参数。因此,当用户登录或注册时,我想将ProjectId (int)
作为参数传递。
用户登录/注册后重定向到我的应用程序后,我希望收到作为参数传递的ProjectId
。
我怎样才能做到这一点?
编辑:添加代码
// The ACR claim is used to indicate which policy was executed
public const string AcrClaimType = "http://schemas.microsoft.com/claims/authnclassreference";
public const string PolicyKey = "b2cpolicy";
private const string OidcMetadataSuffix = "/.well-known/openid-configuration";
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
OpenIdConnectAuthenticationOptions options = new OpenIdConnectAuthenticationOptions
{
// These are standard OpenID Connect parameters, with values pulled from web.config
ClientId = ClientId,
RedirectUri = RedirectUri,
PostLogoutRedirectUri = RedirectUri,
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = AuthenticationFailed,
RedirectToIdentityProvider = OnRedirectToIdentityProvider,
SecurityTokenValidated = OnSecurityTokenValidated
},
Scope = "openid",
ResponseType = "id_token",
// The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
// endpoints from the OpenID Connect metadata endpoint. It is included in the PolicyAuthHelpers folder.
ConfigurationManager = new PolicyConfigurationManager(
string.Format(CultureInfo.InvariantCulture, AadInstance, Tenant, "/v2.0", OidcMetadataSuffix),
new[] { SignUpPolicyId, SignInPolicyId, ProfilePolicyId }),
// This piece is optional - it is used for displaying the user's name in the navigation bar.
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
}
};
app.UseOpenIdConnectAuthentication(options);
}
private Task OnRedirectToIdentityProvider(
RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var currentPolicy =
notification.OwinContext.Authentication.AuthenticationResponseRevoke.AuthenticationTypes
.FirstOrDefault(x => x.StartsWith("b2c"));
notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.Split('?')[0];
notification.ProtocolMessage.Parameters.Add("p", currentPolicy);
}
else
{
**// The value right now for the state is sort of "hijacked" and assigned by Microsoft**
//notification.ProtocolMessage.Parameters["state"] = "OpenIdConnect.AuthenticationProperties=sRt-teBcxsd239viWo...... ";
var currentPolicy = notification.OwinContext.Authentication.AuthenticationResponseChallenge.Properties
.Dictionary[PolicyKey];
notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.Split('?')[0];
notification.ProtocolMessage.Parameters.Add("p", currentPolicy);
}
return Task.FromResult(0);
}
private async Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
await MyClass.CreatePrincipal(notification.AuthenticationTicket.Identity);
}
private Task AuthenticationFailed(
AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
notification.Response.Redirect("/Home/Error?message=" + notification.Exception.Message);
return Task.FromResult(0);
}
答案 0 :(得分:4)
与Gaurav的建议相似,但增加了一些特殊注意事项。基本上,状态是由Owin中间件使用的,所以当你可以注入自己的东西时,你需要确保在Owin中间件试图使用它之前将其还原,否则你会得到auth错误。
这实际上是我回答了一个非常相似的问题:
Custom parameter with Microsoft.Owin.Security.OpenIdConnect and AzureAD v 2.0 endpoint
在Startup.Auth.cs中,当您设置OpenIdConnectAuthenticationOptions时,您需要添加以下内容:
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
//...
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = OnRedirectToIdentityProvider,
MessageReceived = OnMessageReceived
},
});
使用RedirectToIdentityProvider注入您的参数,类似于:
private static Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
var stateQueryString = notification.ProtocolMessage.State.Split('=');
var protectedState = stateQueryString[1];
var state = notification.Options.StateDataFormat.Unprotect(protectedState);
state.Dictionary.Add("mycustomparameter", "myvalue");
notification.ProtocolMessage.State = stateQueryString[0] + "=" + notification.Options.StateDataFormat.Protect(state);
return Task.FromResult(0);
}
然后使用MessageReceived来提取它,如下所示:
private static Task OnMessageReceived(MessageReceivedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
string mycustomparameter;
var protectedState = notification.ProtocolMessage.State.Split('=')[1];
var state = notification.Options.StateDataFormat.Unprotect(protectedState);
state.Dictionary.TryGetValue("mycustomparameter", out mycustomparameter);
return Task.FromResult(0);
}
你显然需要改进/加强这个,但这应该让你去。
答案 1 :(得分:2)
您可以将ProjectId
参数作为State
参数的值传递。请参阅以下示例代码:
Notifications = new OpenIdConnectAuthenticationNotifications()
{
RedirectToIdentityProvider = context =>
{
redirectUri = string.Format("{0}/", System.Web.HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority));
postLogoutRedirectUri = redirectUri + "sign-out";
context.ProtocolMessage.RedirectUri = redirectUri;
context.ProtocolMessage.PostLogoutRedirectUri = postLogoutRedirectUri;
context.ProtocolMessage.State = "Your Project Id";
return Task.FromResult(0);
},
AuthorizationCodeReceived = context =>
{
var projectId = context.ProtocolMessage.State;//Retrieve the state in AuthorizationCodeReceived event.
return Task.FromResult(0);
}
}
};
<强>更新强>
基本上State
接受字符串参数。在我们的项目中,我们需要在州内提供许多价值。我们在那里做的是创建一个管道分隔的字符串并将其作为状态传递。当我们收到状态时,我们只需将其转换为数组并使用适当的元素。类似的东西:
var state = "param1|param2|...|paramx";
你可以做的其他事情是创建一个状态对象(一个带有一些属性的简单类),将其序列化为JSON,将其转换为base64字符串,并在正确地对其进行url编码后将该编码字符串作为状态传递。当您收到状态时,您可以执行相反的过程,获取状态对象并使用它的属性值。
答案 2 :(得分:1)
只需在RedirectToIdentityProvider中添加context.ProtocolMessage.SetParameter(<ParameterName>, <value>);
Notifications = new OpenIdConnectAuthenticationNotifications()
{
RedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("prompt", "login");
return Task.FromResult(0);
},
}
};