我正在尝试建立一个ASP。NET MVC 5应用程序,使用Azure AD进行身份验证。但是,一旦用户通过身份验证,我需要使用aspnet_membership Microsoft Identity设置来获取经过身份验证的登录用户的声明。我们不想在Azure AD设置中维护角色和声明,也不想使用MS Graph。
我在VS 2017中使用个人用户帐户创建了一个MVC 5.0项目,这反过来又为我在SQL Server数据库中创建了aspnet_membership数据库。
我还创建了一个单独的MVC 5.0项目,并在Azure AD中注册了应用程序,我有ClientID等,该项目也运行良好。现在我试着把两者结合起来,我有点迷失了,怀疑我的想法是否正确。
基本上,一旦用户登录到Microsoft Azure AD登录页面,我重定向到本地注册页面,当用户注册时只有最少的信息,包括一些角色,然后我将在AspNetUsers/Claims表中做一个条目,我必须将这些声明附加到主体。在该用户的后续登录时,我必须在身份验证后加载蛤蜊。
你能帮我指出这种场景的任何样本吗,因为我在这里读到的大多数建议使用Microsoft Graph。但是我们的角色太复杂了,我们决定只使用本地身份aspnet_membership数据库进行授权(roles as Claims)。
感谢这对我很有效。
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
string clientId = System.Configuration.ConfigurationManager.AppSettings["ClientId"];
string redirectUri = System.Configuration.ConfigurationManager.AppSettings["RedirectUri"];
string tenant = System.Configuration.ConfigurationManager.AppSettings["Tenant"];
string authority = string.Format(System.Configuration.ConfigurationManager.AppSettings["Authority"], tenant);
var cookieExpiryHours = Int32.Parse(System.Configuration.ConfigurationManager.AppSettings["CookieExpiryHours"]);
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieManager = new SystemWebCookieManager(),
ExpireTimeSpan = TimeSpan.FromMinutes(cookieExpiryHours),
SlidingExpiration=true,
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
Scope = OpenIdConnectScope.OpenIdProfile,
UseTokenLifetime = false,
// ResponseType is set to request the code id_token - which contains basic information about the signed-in user
ResponseType = OpenIdConnectResponseType.CodeIdToken,
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed,
SecurityTokenValidated = OnSecurityTokenValidated,
}
}
);
}
private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
var OIDClaimDesc = "http://schemas.microsoft.com/identity/claims/objectidentifier";
var claims = context.AuthenticationTicket.Identity.Claims;
var cookieExpiryHours = Int32.Parse(System.Configuration.ConfigurationManager.AppSettings["CookieExpiryHours"]);
context.AuthenticationTicket.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(cookieExpiryHours);
context.AuthenticationTicket.Properties.IsPersistent = false;
var owinContext = context.OwinContext;
var userIdentity = context.AuthenticationTicket.Identity;
var userClaims = userIdentity as ClaimsIdentity;
var firstName = userClaims?.FindFirst(ClaimTypes.GivenName)?.Value ?? string.Empty;
var lastName = userClaims?.FindFirst(ClaimTypes.Surname)?.Value ?? string.Empty;
var email = userClaims?.FindFirst(ClaimTypes.Email)?.Value ?? string.Empty;
var objID = Guid.Parse(userClaims.FindFirst(OIDClaimDesc).Value);
var user = new UserService().GetUser(objID, email);
if (user is null)//This user has just wandered in to the site or the admins have not added this user in the DB yet. Just redirect them back to log out
{
owinContext.Authentication.Challenge();
return Task.FromResult(0);
}
if (userIdentity.IsAuthenticated)
{
userIdentity.AddClaim(new Claim(ClaimTypes.GivenName, firstName));
userIdentity.AddClaim(new Claim(ClaimTypes.Surname, lastName));
userIdentity.AddClaim(new Claim(ClaimTypes.Email, email));
userIdentity.AddClaim(new Claim("AzureID", objID.ToString()));
userIdentity.AddClaim(new Claim(ClaimTypes.Role, "user"));
}
new UserService().UpdateUser(objID, firstName, lastName, email);
foreach (var claim in user.UserClaims)
{
if (!claim.ClaimType.Equals(ClaimTypes.GivenName, StringComparison.OrdinalIgnoreCase)
&& !claim.ClaimType.Equals(ClaimTypes.Surname, StringComparison.OrdinalIgnoreCase))
{
userIdentity.AddClaim(new Claim(ClaimTypes.Role, claim.ClaimValue));
}
}
return Task.FromResult(0);
}
/// <summary>
/// Handle failed authentication requests by redirecting the user to the home page with an error in the query string
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
var code = "IDX21323";
if (context.Exception.Message.Contains(code)) //I need this, as under certain conditions, the auth process was going on an infinite loop.
{
context.HandleResponse();
context.OwinContext.Authentication.Challenge();
}
return Task.FromResult(true);
}
}
public UserViewModel GetUser(Guid guid, string email)
{
var model = new UserViewModel();
using (var ctxt = new DBContext())
{
var user = ctxt.Users.Where(x => (x.Email == email || x.OID==guid) && x.IsActive).FirstOrDefault();
if (user == null)
return null;
var claims = ctxt.UserClaims.Where(x => x.UserId==user.ID).ToList();
model = Mapper.Map<UserViewModel>(user);
model.UserClaims = Mapper.Map<List<ViewModels.UserClaimViewModel>>(claims);
}
return model;
}