我有一个小型的C#MVC5应用程序,我正在构建并准备添加用户安全模块。 (之前我刚刚创建了一个用于测试角色的会话变量)但是,我的安全需求不适合我所见过的任何预构建的安全模块,即SimpleMembership等。
以下是我的情况和需求摘要:
没有密码 - 用户名/密码验证不
使用带有客户端证书的智能卡在Web服务器级别对用户进行身份验证 - 我不管理服务器,也永远不会看到他们的卡
IIS填充了Request.ClientCertificate和其他几个,这是我有权访问
我的应用程序将拥有专用的用户帐户 - 不使用Windows身份验证等 - 所以更像是用户名/密码系统,而无需输入用户名或密码
服务器通过使用某种形式的Windows身份验证及其智能卡证书来验证它们以访问服务器,但我不能,我只需要接受加载到Request集合中的证书
用户表存储在SQL Server中(现在......)
不希望使用EntityFramework,因为所有应用程序数据都来自Oracle数据库并试图获得批准将身份验证/授权表移入其中并消除两个数据库的工作,并且EF for Oracle不会在我们的环境中工作,所以我改用OleDb :(
实施这样的计划的最佳方法是什么?我开始做的是构建三个表 - Users,Roles和UserRoles - 而Users表包含(string)ClientCertificate的副本。进入的用户将通过拉取Request.ClientCertificate并查找匹配的用户记录,然后从UserRoles获取角色列表来对应用程序进行身份验证。用户对象将存储在包含用户和角色信息的会话中,并且属性将在控制器上用于通过要求某些角色来控制访问。
(我们有另一个使用这种基本方法的应用程序,但它是Linux上的J2EE,所以我不能重复使用它的代码)
但是,我也开始阅读有关IIdentity和IPrincipal的内容,但我并不是100%清楚这是否是我可以使用的东西。显然,我更喜欢使用由专家设计的安全模型。那么我应该使用继承自IIdentity和IPrincipal的自定义类来构建我的身份验证系统吗?或者我应该使用其他方法吗?
完全有可能像SimpleMembership这样的东西可以定制以满足我的需求,但如果是这样的话,我就不会意识到这一点。
感谢您的建议,非常感谢。
答案 0 :(得分:5)
您也可以将Microsoft's Identity用于此类高级方案。身份如此模块化,您可以将任何数据存储用于您想要的任何架构。身份验证的密码不是必须的,您可以实现自己的方案。考虑这个简单的例子:
// imaging this action is called after user authorized by remote server
public ActionResoult Login()
{
// imaging this method gets authorized certificate string
// from Request.ClientCertificate or even a remote server
var userCer=_certificateManager.GetCertificateString();
// you have own user manager which returns user by certificate string
var user=_myUserManager.GetUserByCertificate(userCer);
if(user!=null)
{
// user is valid, going to authenticate user for my App
var ident = new ClaimsIdentity(
new[]
{
// since userCer is unique for each user we could easily
// use it as a claim. If not use user table ID
new Claim("Certificate", userCer),
// adding following 2 claim just for supporting default antiforgery provider
new Claim(ClaimTypes.NameIdentifier, userCer),
new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"),
// an optional claim you could omit this
new Claim(ClaimTypes.Name, user.Name),
// populate assigned user's role form your DB
// and add each one as a claim
new Claim(ClaimTypes.Role, user.Roles[0].Name),
new Claim(ClaimTypes.Role, user.Roles[1].Name),
// and so on
},
DefaultAuthenticationTypes.ApplicationCookie);
// Identity is sign in user based on claim don't matter
// how you generated it Identity take care of it
HttpContext.GetOwinContext().Authentication.SignIn(
new AuthenticationProperties { IsPersistent = false }, ident);
// auth is succeed, without needing any password just claim based
return RedirectToAction("MyAction");
}
// invalid certificate
ModelState.AddModelError("", "We could not authorize you :(");
return View();
}
正如您所看到的,我们授权用户和填充的角色,而不依赖于用户名,密码和任何数据存储,因为我们使用了自己的用户管理器。
一些用法示例:
[Authorize]
public ActionResult Foo()
{
}
// since we injected user roles to Identity we could do this as well
[Authorize(Roles="admin")]
public ActionResult Foo()
{
// since we injected our authentication mechanism to Identity pipeline
// we have access current user principal by calling also
// HttpContext.User
}
这是一个简单的示例,您也可以实现自定义方案扩展IIdenity
。阅读我的其他类似答案,例如this和this,了解更多示例,了解如何按Claims
执行几乎所有操作。
您也可以浏览并下载Token Based Authentication Sample repo作为一个简单的工作示例。
答案 1 :(得分:0)
根据它的声音,用户已经过身份验证,因此在您的控制器中,您只需访问控制器继承的User
基类上的Controller
属性即可。这是属性返回IIPrincipal
,其中有一个名为Identity
的属性,它返回IIdentity
。
因此,例如,如果您想要在控制器中检索当前登录用户的用户名,则可以访问User.Identity.Name
,或者如果您想确保用户已登录,则可以检查User.Identity.IsAuthenticated
。< / p>
你绝对不应该从客户端证书中提取任何内容,本质上服务器应该已经对用户进行了身份验证,你并不关心它是通过证书而不是用户名/密码来完成的。