Mar*_*cus 7 asp.net authentication wif asp.net-mvc-5 asp.net-identity
我正在将SaaS应用程序从Classic ASP迁移到.NET MVC5,并将使用EF6 Database First.最终用户的登录表单可由每个租户自定义(在他们自己的子域上,但指向同一个Web应用程序).我们希望使用现有的数据库架构和新的身份验证和授权过滤器.
例如,一个租户上的用户可以通过输入他们的名字,姓氏和我们系统生成的代码来登录.另一个租户的用户可以通过输入他们的电子邮件地址和密码来登录.此外,每个租户都有一个单独的管理员登录名,该登录名使用用户名和密码.另一个租户可以对远程AD服务器使用LDAP身份验证.
有自定义身份验证的最佳实践方法吗?
几乎每篇文章都提出了不同的实现方法:简单地设置FormsAuthentication.SetAuthCookie
,使用自定义OWIN提供程序,覆盖AuthorizeAttribute
等.
在Classic ASP中,我们查询数据库以找出该租户的登录类型,在登录屏幕上显示相应的字段然后在回发后,检查字段是否与数据库中的内容匹配,然后适当地设置会话变量检查每个页面请求.
谢谢
我发现Identity框架在身份验证选项方面非常灵活.看看这段认证码:
var identity = await this.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie);
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
Run Code Online (Sandbox Code Playgroud)
这是Identity中工厂认证部分的标准运行,您可以在Web上的每个Identity示例中找到它.如果你仔细观察它是非常灵活的 - 身份验证所需要的只是ApplicationUser
框架不关心你得到的对象.
所以在理论上你可以做这样的事情(伪代码,我没有尝试编译这个):
// get user object from the database with whatever conditions you like
// this can be AuthCode which was pre-set on the user object in the db-table
// or some other property
var user = dbContext.Users.Where(u => u.Username == "BillyJoe" && u.Tenant == "ExpensiveClient" && u.AuthCode == "654")
// check user for null
// check if the password is correct - don't have to do that if you are doing
// super-custom auth.
var isCorrectPassword = await userManager.CheckPasswordAsync(user, "enteredPassword");
if (isCorrectPassword)
{
// password is correct, time to login
// this creates ClaimsIdentity object from the ApplicationUser object
var identity = await this.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// now we can set claims on the identity. Claims are stored in cookie and available without
// querying database
identity.AddClaim(new Claim("MyApp:TenantName", "ExpensiveClient"));
identity.AddClaim(new Claim("MyApp:LoginType", "AuthCode"));
identity.AddClaim(new Claim("MyApp:CanViewProducts", "true"));
// this tells OWIN that it can set auth cookie when it is time to send
// a reply back to the client
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
Run Code Online (Sandbox Code Playgroud)
使用此身份验证,您已为用户设置了一些声明 - 它们存储在Cookie中,并且随处可用ClaimsPrincipal.Current.Claims
.声明本质上是键值键对的集合,您可以存储任何您喜欢的内容.
我通常通过扩展方法访问用户的声明:
public static String GetTenantName(this ClaimsPrincipal principal)
{
var tenantClaim = principal.Claims.FirstOrDefault(c => c.Type == "MyApp:TenantName");
if (tenantClaim != null)
{
return tenantClaim.Value;
}
throw new ApplicationException("Tenant name is not set. Can not proceed");
}
public static String CanViewProducts(this ClaimsPrincipal principal)
{
var productClaim = principal.Claims.FirstOrDefault(c => c.Type == "MyApp:CanViewProducts");
if (productClaim == null)
{
return false;
}
return productClaim.Value == "true";
}
Run Code Online (Sandbox Code Playgroud)
因此,在您的控制器/视图/业务层中,您始终可以调用ClaimsPrincipal.Current.GetTenantName()
,在这种情况下,您将获得"ExpensiveClient".
或者,如果您需要检查是否为用户启用了特定功能,则可以执行此操作
if(ClaimsPrincipal.Current.CanViewProducts())
{
// display products
}
Run Code Online (Sandbox Code Playgroud)
您可以自行决定如何存储用户属性,但只要您将其设置为Cookie上的声明,它们就可用.
或者,您可以为每个用户向数据库添加声明:
await userManager.AddClaimAsync(user.Id, new Claim("MyApp:TenantName", "ExpensiveClient"));
Run Code Online (Sandbox Code Playgroud)
这将使索赔持续存入数据库.默认情况下,Identity框架在用户登录时会将此声明添加到用户,而无需手动添加.
但要注意,你不能在cookie上设置太多的声明.Cookie具有浏览器设置的4K限制.身份cookie加密的工作方式使编码文本增加了大约1.1,因此您可以拥有大约3.6K的代表声明的文本.我在这里遇到了这个问题
更新
要通过声明控制对控制器的访问,您可以在控制器上使用以下过滤器:
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
public string Name { get; private set; }
public ClaimsAuthorizeAttribute(string name)
{
Name = name;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
var user = HttpContext.Current.User as ClaimsPrincipal;
if (user.HasClaim(Name, Name))
{
base.OnAuthorization(filterContext);
}
else
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary()
{
{"controller", "errors"},
{"action", "Unauthorised"}
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后在控制器上使用此属性或单独执行此操作:
[ClaimsAuthorize("Creating Something")]
public ActionResult CreateSomething()
{
return View();
}
Run Code Online (Sandbox Code Playgroud)
用户需要对其进行"创建内容"声明才能访问此操作,否则他们将被重定向到"未经身份验证"页面.
最近我玩了索赔认证并制作了类似于你的要求的原型应用程序.请查看简单版本:https://github.com/trailmax/ClaimsAuthorisation/tree/SimpleClaims其中声明是为每个用户单独存储的.或者有更复杂的解决方案,其中声明属于角色,当用户登录时,分配给用户的角色声明:https://github.com/trailmax/ClaimsAuthorisation/tree/master
归档时间: |
|
查看次数: |
7462 次 |
最近记录: |