如何使用 Identity & Entity Framework 在 .NET Core 2.0 中管理身份验证和授权
How to manage authentication and authroization in .NET Core 2.0 with Identity & Entity Framework
简介
过去几天我一直在从事小型宠物项目,目标是学习 .NET Core 2.0,其身份由 Entity Framework Core 支持。这是一个典型的 "WebAPI" 类型的项目,具有基于 cookie 的身份验证和基于声明的授权。它被一些客户端应用程序 (SPA) 使用。
代码
授权和身份验证流程在 Startup.cs
中以这种方式配置
services
.AddIdentity<ApplicationUser, IdentityRole> ()
.AddEntityFrameworkStores<ApplicationDbContext> ()
.AddDefaultTokenProviders ();
services
.AddAuthentication (sharedOptions => {
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie ();
我的登录控制器操作如下所示:
[HttpPost]
[Route ("login")]
public async Task<IActionResult> Login ([FromBody] LogInCredentialsModel credentials) {
// Get User for given UserName
var user = await userManager.Users.FirstOrDefaultAsync (p => p.UserName == credentials.UserName);
//User not found
if (user == default (ApplicationUser))
return StatusCode (400);
// Check if password is correct
var result = await signInManager.PasswordSignInAsync (user, credentials.Password, true, false);
if (result.Succeeded) {
//Basic claims with Name and Email
List<Claim> claims = new List<Claim> {
new Claim (ClaimTypes.Name, user.UserName),
new Claim (ClaimTypes.Email, user.Email)
};
var userRoles = await this.GetUserRoles (user); // Custom helper method to get list of user roles
// Add Role claims
foreach (var role in userRoles) {
claims.Add (new Claim (ClaimTypes.Role, role));
}
ClaimsIdentity identity = new ClaimsIdentity (claims, CookieAuthenticationDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new ClaimsPrincipal (identity);
// Sign in using cookie scheme
await HttpContext.SignInAsync (CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties {
IsPersistent = true,
});
return Ok ();
} else {
return StatusCode (400);
}
}
问题
- 这些声明将存储在加密的用户 cookie 中。这意味着,如果我从用户那里删除了一些声明并且他没有重新登录,他仍然会分配旧的声明。我该如何防止呢?还是我误解了设计?
- 用户将用户名和密码传递给登录路由,然后用于登录。在我的代码中,我必须首先找到具有给定用户名的用户(第一次数据库命中),然后尝试使用 SignInManager 使用密码登录(第二次数据库命中),读取角色(第三次数据库命中)以构建 ClaimsPrincipal,然后使用 HttpContext.SignInAsync 创建具有正确声明的用户 cookie。我个人觉得我遗漏了一些东西,结果我的代码过于复杂,而且至少有一个数据库查询可以保存在这里。如何改进这部分?
你的两个问题的答案都非常基础,所以也许你应该花更多时间阅读文档以更好地处理这个问题。也就是说:
是的。你是对的。当您更改声明时,您也应该将用户注销。然后,您可以选择让他们再次自动登录,无需用户干预,或提示用户 re-login(取决于您的个人安全偏好)。
你为什么要手动做这些?您只需要:
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
这会自动对密码进行哈希处理,尝试使用该用户名(电子邮件地址)和经过哈希处理的密码检索用户,如果成功,然后使用所有这些信息创建 ClaimsPrincipal
。一个就完成了。
简介
过去几天我一直在从事小型宠物项目,目标是学习 .NET Core 2.0,其身份由 Entity Framework Core 支持。这是一个典型的 "WebAPI" 类型的项目,具有基于 cookie 的身份验证和基于声明的授权。它被一些客户端应用程序 (SPA) 使用。
代码
授权和身份验证流程在 Startup.cs
中以这种方式配置services
.AddIdentity<ApplicationUser, IdentityRole> ()
.AddEntityFrameworkStores<ApplicationDbContext> ()
.AddDefaultTokenProviders ();
services
.AddAuthentication (sharedOptions => {
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie ();
我的登录控制器操作如下所示:
[HttpPost]
[Route ("login")]
public async Task<IActionResult> Login ([FromBody] LogInCredentialsModel credentials) {
// Get User for given UserName
var user = await userManager.Users.FirstOrDefaultAsync (p => p.UserName == credentials.UserName);
//User not found
if (user == default (ApplicationUser))
return StatusCode (400);
// Check if password is correct
var result = await signInManager.PasswordSignInAsync (user, credentials.Password, true, false);
if (result.Succeeded) {
//Basic claims with Name and Email
List<Claim> claims = new List<Claim> {
new Claim (ClaimTypes.Name, user.UserName),
new Claim (ClaimTypes.Email, user.Email)
};
var userRoles = await this.GetUserRoles (user); // Custom helper method to get list of user roles
// Add Role claims
foreach (var role in userRoles) {
claims.Add (new Claim (ClaimTypes.Role, role));
}
ClaimsIdentity identity = new ClaimsIdentity (claims, CookieAuthenticationDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new ClaimsPrincipal (identity);
// Sign in using cookie scheme
await HttpContext.SignInAsync (CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties {
IsPersistent = true,
});
return Ok ();
} else {
return StatusCode (400);
}
}
问题
- 这些声明将存储在加密的用户 cookie 中。这意味着,如果我从用户那里删除了一些声明并且他没有重新登录,他仍然会分配旧的声明。我该如何防止呢?还是我误解了设计?
- 用户将用户名和密码传递给登录路由,然后用于登录。在我的代码中,我必须首先找到具有给定用户名的用户(第一次数据库命中),然后尝试使用 SignInManager 使用密码登录(第二次数据库命中),读取角色(第三次数据库命中)以构建 ClaimsPrincipal,然后使用 HttpContext.SignInAsync 创建具有正确声明的用户 cookie。我个人觉得我遗漏了一些东西,结果我的代码过于复杂,而且至少有一个数据库查询可以保存在这里。如何改进这部分?
你的两个问题的答案都非常基础,所以也许你应该花更多时间阅读文档以更好地处理这个问题。也就是说:
是的。你是对的。当您更改声明时,您也应该将用户注销。然后,您可以选择让他们再次自动登录,无需用户干预,或提示用户 re-login(取决于您的个人安全偏好)。
你为什么要手动做这些?您只需要:
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
这会自动对密码进行哈希处理,尝试使用该用户名(电子邮件地址)和经过哈希处理的密码检索用户,如果成功,然后使用所有这些信息创建
ClaimsPrincipal
。一个就完成了。