Is there a simple way to implement Single Sign On

2019-08-10 17:58发布

问题:

This question already has an answer here:

  • ASP.NET Identity Cookie across subdomains 4 answers

Scenario:

Two separate web projects, running om these domains:

  • account.ilovepandas.com
  • ilovepandas.com

Using ASP.Net Identity, is there a simple way in MVC5 to implement a shared login, so that if the user is logged in to ilovepandas.com and goes to account.ilovepandas.com, he will already be authenticated?

I have done research on the topic, and there are some quite complicated solutions out there, like Thinktecture, OWIN authorization server. My hope is, that since MVC4-5 gave us a big overhaul of Identity, maybe there is an easier solution now, that I have just not been able to find.

It would seem to me to be as simple as letting them share the auth-cookie.

回答1:

TL;DR: Assuming both apps share the same top-level domain, you can share the authentication cookie. Set the domain on the cookie, and share any keys necessary to decrypt it between the apps.

Here, I'm going to assume you're using FormsAuthentication.

1) Add the domain attribute to the authentication/forms section:

<authentication mode="Forms">
  <forms loginUrl="~/account/login"
         timeout="2880"
         defaultUrl="~/"
         slidingExpiration="true"
         protection="All"
         domain=".yourdomain.tld"
         name="YOUR_COOKIE_NAME" />

Note the leading period on the domain.

2) In order for both apps to be able to decrypt the cookie, you need to add a machineKey to both, and use the same validation and encryption keys:

<machinekey compatibilitymode="Framework45"
            validation="HMACSHA256"
            validationkey="YOURVALIDATIONKEYHERE"
            decryption="AES"
            decryptionkey="YOURDECRYPTIONKEYHERE" />

You can use the machine key tool in IIS Manager (assuming you have access to the web server), or whatever other tool gets you valid keys. If you need a suggestion, I built an app you can use here, which links to it's Github project if you want to generate your own keys.

For completeness:

Here's the class that will generate valid keys:

public class KeyGenerator
{
    public string GenerateKey(int length, bool useUpperCase = true)
    {
        byte[] buffer = new byte[length];
        var randomNumberGenerator = new RNGCryptoServiceProvider();
        randomNumberGenerator.GetBytes(buffer);

        return ToHexString(buffer, true);
    }

    private static string ToHexString(byte[] bytes, bool useUpperCase = false)
    {
        var hex = string.Concat(bytes.Select(b => b.ToString(useUpperCase ? "X2" : "x2")));

        return hex;
    }
}

And you would use something like this to get your keys:

var generator = new KeyGenerator();

/* 512 bits = 64 bytes (512 / 8) */
string validationKey = generator.GenerateKey(64);

/* 256 bits = 32 bytes (256 / 8) */
string decryptionKey = generator.GenerateKey(32);