How to do Active Directory authentication in Razor

2019-04-01 19:17发布

I am doing a simple website with Razor. Currently, I have database-based authentication that works, as follows:

In _AppStart.chtml:

WebSecurity.InitializeDatabaseConnection("db_connection",
       "users", "id", "username", true);

In login.cshtml page:

    username = Request["username"];
    password = Request["password"];

    if (WebSecurity.Login(username, password, true))
    {
        Response.Redirect("/admin");
    }
    else
    {
        errorMessage = "Login was not successful.";
    }

In protected CSHTML pages, I have the following at the top of a page:

if (!WebSecurity.IsAuthenticated)
{
    Response.Redirect("/login.cshtml");
}

Everything is pretty simple and works well. Now I would like to add authentication with AD. I don't know how to do it.

I came from the Java world with many years of experience. For this simple website, I do not need MVC architecture. I need simple things similar to the above (if possible). I need to do authentication just within the login.cshtml file. I googled a lot and am unable to find a tutorial (so that I can copy and paste) for what I need.

Any pointers or help is really appreciated!

Thanks and Regards

Update: This application sits on the internal network.

Update 2: Here is the code I have after successfully implemented X3074861X's code

if (IsPost)
{
    username = Request["username"];
    password = Request["password"];
    var domain = "domain";
    var host = "host";
    var port = "389";

    LdapConnection ldapConnection = new LdapConnection(host + ":" + port);
    try
    {
        // authenticate the username and password
        using (ldapConnection)
        {
            // pass in the network creds, and the domain.
            var networkCredential = new NetworkCredential(username, password, domain);
            // if we're using unsecured port 389, set to false. If using port 636, set this to true.
            ldapConnection.SessionOptions.SecureSocketLayer = false;
            // since this is an internal application, just accept the certificate either way
            ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };
            // to force NTLM\Kerberos use AuthType.Negotiate, for non-TLS and unsecured, just use AuthType.Basic
            ldapConnection.AuthType = AuthType.Basic;
            // this is where the authentication occurs
            ldapConnection.Bind(networkCredential);

            //check local database to make sure the user is one of we allowed
            if (WebSecurity.Login(username, "fixed-password, just to check whether someone is on the list of allowed people", true))
            {
                Response.Redirect("/admin");
            }
            else
            {
                errorMessage = "Login was not successful.";
            }
        }
    }

    catch (LdapException exception)
    {
        //Authentication failed, exception will dictate why
        errorMessage = "Login was not successful.";
    }

Some explanation. I dont have control over the AD and so I can only authenticate users against it. I still have a little local database that indicates who can access the app. Everyone with access to the app has the same rights.

Thanks and credit goes to X3074861X.

1条回答
Animai°情兽
2楼-- · 2019-04-01 19:51

Since this is an internal application, and you're looking for something simple, I would consider writing a single class to do the Active Directory authentication. You're going to need a couple things though, in order for this to work :

  • A reference to System.DirectoryServices.Protocols in your project.
  • The IP or DNS name of your Active Directory server. We'll call it host in the code below.
  • The port it's running on (LDAPS will be port 636, basic LDAP will be port 389). We'll call it port in the code below.
  • The Domain to which your users belong. We'll call it domain in the code below.

Now that you have that, you can wire this up to check the credentials from the request against your AD instance. I would try something like this :

// the username and password to authenticate
username = Request["username"];
password = Request["password"];

// define your connection
LdapConnection ldapConnection = new LdapConnection("host:port");

try
{
      // authenticate the username and password
      using (ldapConnection)
      {
          // pass in the network creds, and the domain.
          var networkCredential = new NetworkCredential(username, password, domain);

          // if we're using unsecured port 389, set to false. If using port 636, set this to true.
          ldapConnection.SessionOptions.SecureSocketLayer = false;

          // since this is an internal application, just accept the certificate either way
          ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };

          // to force NTLM\Kerberos use AuthType.Negotiate, for non-TLS and unsecured, just use AuthType.Basic
          ldapConnection.AuthType = AuthType.Basic;

          // authenticate the user
          ldapConnection.Bind(networkCredential);
      }
      catch (LdapException ldapException)
      {
          //Authentication failed, exception will dictate why
      }
}

Also, in the same way you'd communicate an authorization issue before, the ldapException can tell you why the call failed. If you want to display custom messaging, I would check the LdapException.ErrorCode property, and maybe create a case statement of return messages based on the error codes.

Or, you could just output LdapException.Message directly to the page - either way, that will at least dictate to the user why their login didn't work.

查看更多
登录 后发表回答