我配置了一个使用AD FS的Web App,为此我使用了OWIN。
登录时,一切正常。如果我是域用户并进入该网站,则会自动连接。
但我想要的是在登录后自己处理用户和角色。
所以我想用这个AD帐户检查我的数据库中是否存在用户(此过程将在另一个应用程序登录之前生成)
我想使用Microsoft的Identity来处理声明(角色和权限)。但我不明白如何使用我的代码来处理来自AD FS(使用Ws-Federation)的成功连接,并添加验证并填写正确的角色。
我在ConfigureAuth中的代码:
public partial class Startup
{
private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"];
private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"];
private NLogLoggingService _loggingService;
public void ConfigureAuth(IAppBuilder app)
{
_loggingService = new NLogLoggingService("Startup");
_loggingService.Debug("ConfigureAuth");
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = adfsMetadata,
//CallbackPath = PathString.FromUriComponent("/Account/TestCallback"),
// https://msdn.microsoft.com/en-us/library/microsoft.owin.security.authenticationmode(v=vs.113).aspx
AuthenticationMode = AuthenticationMode.Passive,
//Notifications = new WsFederationAuthenticationNotifications
//{
//}
});
}
在Web.config中,realm是我的Web App(https://ssoadfs.test)的链接,adfsMetadata是AD FS的metadata.xml链接。
在AD FS连接后设置我的角色和登录逻辑的方法是什么?
架构,我在想什么:
编辑: 经过一些尝试,我无法处理任何成功的回调。我不想在HomeController中处理角色...
我上次的Auth配置:
_loggingService = new NLogLoggingService("Startup");
_loggingService.Debug("ConfigureAuth");
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationUser.ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.SetDefaultSignInAsAuthenticationType(DefaultAuthenticationTypes.ApplicationCookie);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
Provider = new CookieAuthenticationProvider
{
OnResponseSignIn = ctx =>
{
_loggingService.Debug("OnResponseSignIn");
ctx.Identity = TransformClaims(ctx, app);
},
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = adfsMetadata,
Caption = "Active Directory",
CallbackPath = PathString.FromUriComponent("/Account/TestCallback"),
Notifications = new WsFederationAuthenticationNotifications
{
SecurityTokenValidated = n =>
{
new NLogLoggingService("Startup").Debug("SecurityTokenValidated");
var incomingClaimsFromAdfs = n.AuthenticationTicket.Identity.Claims.ToList();
var incomingClaimsHasNameIdentifier =
incomingClaimsFromAdfs.Any(
c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier);
_loggingService.Debug("SecurityTokenValidated - incomingClaimsHasNameIdentifier: " +
incomingClaimsHasNameIdentifier);
if (!incomingClaimsHasNameIdentifier)
{
var emailClaim =
incomingClaimsFromAdfs.First(c => c.Type == System.Security.Claims.ClaimTypes.Name);
_loggingService.Debug(emailClaim.Value);
}
//if (!incomingClaimsHasNameIdentifier)
//{
// var emailClaim = incomingClaimsFromAdfs.First(c => c.Type == System.Security.Claims.ClaimTypes.Name);
// incomingClaimsFromAdfs.Add();
// IUser user = await this.UserStore.FindByNameOrEmailAsync(userNameOrEmailAddress);
// if ((Entity<long>)user == (Entity<long>)null)
// LoginResult = new ApplicationUserManager.LoginResult(LoginResultType.InvalidUserNameOrEmailAddress, default(IUser));
// //else if (!loggedInFromExternalSource && new PasswordHasher().VerifyHashedPassword(user.Password, plainPassword) != PasswordVerificationResult.Success)
// // LoginResult = new UserManager<TTenant, TRole, TUser>.LoginResult(LoginResultType.InvalidPassword, user);
// else
// LoginResult = await this.CreateLoginResultAsync(user, tenant);
//}
//else
//{
// throw new ApplicationException("Get ADFS to provide the NameIdentifier claim!");
//}
//var normalizedClaims = incomingClaimsFromAdfs.Distinct(new ClaimComparer());
//var claimsIdentity = new ClaimsIdentity(normalizedClaims, n.AuthenticationTicket.Identity.AuthenticationType);
//n.AuthenticationTicket = new AuthenticationTicket(claimsIdentity, n.AuthenticationTicket.Properties);
return Task.FromResult(0);
}
}
});
在这段代码中,我尝试了CallbackPath(我的日志中没有出现任何内容),WsFederationAuthenticationNotifications.SecurityTokenValidated(我的日志中没有出现任何内容),CookieAuthenticationProvider.OnResponseSignIn(同样没有发生)
在HomeController中,我能够拥有Identity.Name:
public ActionResult Index()
{
if (HttpContext.GetOwinContext().Authentication.User.Identity.IsAuthenticated)
{
new NLogLoggingService("Home").Debug("User is authenticated");
}
return View();
}
我是否遗漏了在CookieAuthenticationOptions中使用通知或提供商的内容???
答案 0 :(得分:1)
如果您使用ASP.NET Identity 2.0
或更高版本,则可以使用与下面所示类似的方法。请注意,此方法将GroupRoles
分配给用户,而不是逐个分配每个角色。您可以根据需要更换必要的零件。
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
ApplicationGroupManager groupManager = new ApplicationGroupManager();
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
//Assign Roles to the current User
ApplicationUser user = UserManager.FindByName(model.UserName);
//If the user is registered in the system (ASP.NET Identity) add record to AspNetUsers table
if (user != null)
{
//Returns Group Id and Role Id by using User Id parameter
var userGroupRoles = groupManager.GetUserGroupRoles("bfd9730e-2093-4fa0-89a2-226e301d831b");
foreach (var role in userGroupRoles)
{
string roleName = RoleManager.FindById(role.ApplicationRoleId).Name;
UserManager.AddToRole(user.Id, roleName);
}
}
else
{
//crate new user
//first retrieve user info from LDAP:
// Create an array of properties that we would like and add them to the search object
string[] requiredProperties = new string[] { "samaccountname", "givenname", "sn", "mail", "physicalDeliveryOfficeName", "title" };
var userInfo = CreateDirectoryEntry(model.UserName, requiredProperties);
var newUser = new ApplicationUser();
newUser.UserName = userInfo.GetDirectoryEntry().Properties["samaccountname"].Value.ToString();
newUser.Name = userInfo.GetDirectoryEntry().Properties["givenname"].Value.ToString();
newUser.Surname = userInfo.GetDirectoryEntry().Properties["sn"].Value.ToString();
newUser.Email = userInfo.GetDirectoryEntry().Properties["mail"].Value.ToString();
newUser.EmailConfirmed = true;
newUser.PasswordHash = null;
var result = await UserManager.CreateAsync(newUser);
if (result.Succeeded)
{
//If the user is created ...
}
//Assign user group (and roles)
var defaultGroup = "751b30d7-80be-4b3e-bfdb-3ff8c13be05e";
groupManager.SetUserGroups(newUser.Id, new string[] { defaultGroup });
}
return this.RedirectToAction("Index", "Issue");
}
this.ModelState.AddModelError(string.Empty, "Wrong username or password!");
return this.View(model);
}
static SearchResult CreateDirectoryEntry(string sAMAccountName, string[] requiredProperties)
{
DirectoryEntry ldapConnection = null;
try
{
ldapConnection = new DirectoryEntry("LDAP://OU=******, DC=******, DC=******", "acb@xyz.com", "YourPassword");
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;
DirectorySearcher search = new DirectorySearcher(ldapConnection);
search.Filter = String.Format("(sAMAccountName={0})", sAMAccountName);
foreach (String property in requiredProperties)
search.PropertiesToLoad.Add(property);
SearchResult result = search.FindOne();
//SearchResultCollection searchResultCollection = search.FindAll(); //You can also retrieve all information
if (result != null)
{
return result;
}
else {
return null;
//Console.WriteLine("User not found!");
}
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return null;
}
希望这会有所帮助...