如何使用证书而不是密码进行身份验证

本文关键字:密码 身份验证 何使用 证书 | 更新日期: 2023-09-27 18:07:42

我有一个小的c# MVC5应用程序,我正在构建,并准备添加用户安全模块给它。(之前我只是为测试角色创建了一个会话变量)然而,我的安全需求不适合我所见过的任何预构建的安全模块,例如simplembership等。

以下是我的情况和需求的总结:

  • 没有密码——username/password auth is not allowed

  • 用户使用带有客户端证书的智能卡在web服务器级别进行身份验证——我不管理服务器,也永远不会看到他们的卡

  • IIS填充请求。ClientCertificate和其他一些,这是我可以访问的所有

  • 我的应用程序将有专用的用户帐户-不使用Windows认证等-所以更像一个用户名/密码系统,而无需输入用户名或密码

  • 服务器正在对他们进行身份验证,通过使用某种形式的Windows认证和他们的智能卡证书来访问服务器,但是我不能,我只需要接受加载到请求集合

  • 中的证书
  • 用户表存储在SQL Server(目前…)

  • 不喜欢使用EntityFramework,因为所有的应用程序数据都来自Oracle数据库,并试图获得批准,将身份验证/授权表移动到其中,并消除从两个数据库工作,EF for Oracle在我们的环境中不起作用,所以我使用OleDb代替:(

实现这样一个方案的最好方法是什么?我开始做的是构建三个表——Users、Roles和UserRoles——Users表保存(字符串)ClientCertificate的副本。进入应用程序的用户将通过拉出请求来进行身份验证。并查找匹配的Users记录,然后从UserRoles获取角色列表。用户对象将存储在包含用户和角色信息的会话中,而属性将在控制器上使用,通过要求特定角色来控制访问。

(我们有另一个应用程序使用这个基本方法,但它是Linux上的J2EE,所以我不能只是重用它的代码)

然而,我也开始阅读关于IIdentity和IPrincipal,但我不是100%清楚是否这是我可以使用的东西。显然,我更喜欢使用专家设计的安全模型。那么,我应该使用从IIdentity和IPrincipal继承的自定义类来构建我的身份验证系统吗?或者我应该用别的方法吗?

完全有可能像simplememmembership这样的东西可以定制以满足我的需求,但如果是这样的话,我不知道。

谢谢你的建议,非常感谢。

如何使用证书而不是密码进行身份验证

对于这种高级场景,您也可以使用Microsoft的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。阅读我的其他类似的答案,比如这个和这个,了解更多的例子,看看你如何通过Claims做几乎所有的事情。

您也可以浏览并下载基于令牌的身份验证示例repo作为一个简单的工作示例。

从它的声音用户已经通过身份验证,因此在您的控制器中,您可以简单地访问您的控制器继承的Controller基类上的User属性。这个属性返回一个IIPrincipal,它有一个名为Identity的属性返回一个IIdentity

因此,例如,如果您想检索当前登录用户的用户名,您将访问User.Identity.Name,或者如果您想确保用户已登录,您可以检查User.Identity.IsAuthenticated

你绝对不应该从客户端证书中提取任何东西,本质上服务器应该已经对用户进行了身份验证,你不关心它是通过证书而不是用户名/密码完成的