简体   繁体   中英

How to redirect and auto login user

How can I redirect a user from one Asp.net Mvc site to another Asp.net MVC site and automatically log them in?

The situation is that we will have some customers that need to go to one site and some that will need to go to the other. I've been asked to make it so that when customers are redirected to the correct site that they are also auto logged in to the site they are redirected to.

Assuming you don't want to integrate existing single sign-on solution and that you are using forms authentication for both sites and those sites are not on the same domain. The forms authentication in MVC is done via cookie. So the task is when you're logged in to Site1 to create authentication cookie on Site2.

Usually you craft a request to Site2 like:

/Impersonate/Start?encryptedToken=some_encrypted_stuff

And Site2 handling it like:

[DataContract]
public class Token
{
  [DataMember(Name = "u")]
  public string UserName { get; set; }
  [DataMember(Name = "t")]
  public DateTime TimeStamp { get; set; }
  [DataMember(Name = "m")]
  public string Magic { get; set; }
  public Token()
  {
    Magic = MAGIC;
    TimeStamp = DateTime.Now;
  }
  public const string MAGIC = "SOME_RANDOM_STRING";
}

public class ImpersonateController : Controller
{
  [HttpGet]
  public ActionResult Start(string encryptedToken)
  {
    // symmetric encryption - hopefully you know how to do it :)
    string decryptedToken = Decrypt(encryptedToken);
    var serializer = new DataContractJsonSerializer(typeof(Token));
    Token token;
    using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(decryptedToken)))
    {
      token = serializer.ReadObject(stream);
    }
    if (!string.Equals(token.Magic, Token.MAGIC) || 
      (DateTime.Now - token.TimeStap).TotalMinutes > 1))
    {
      // magic doesn't match or timestamp is too old
      throw new Exception("Invalid token.");
    }
    FormsAuthentication.SetAuthCookie(token.UserName, true);
    return new HttpStatusCodeResult(HttpStatusCode.OK); 
  }
}

Maybe needless to say /Impersonate/Start should be under https. As for crafting the request - you can put it directly into view & make request via json.

In Site1:

public class LoginController : Controller
{
  public ActionResult Login(string userName, string password)
  {
     // ... validate user logs to site 1 etc
     var site2UserName = userName;
     var token = new Token { UserName = site2UserName };
     var serializer = new DataContractJsonSerializer(typeof(Token));
     string decryptedToken;
     using (var stream = new MemoryStream())
     {
       serializer.WriteObject(stream, token);
       decryptedToken = Encoding.UTF8.GetString(stream.ToArray());
     }
     // symmetrical encryption
     return new View(new LoginMode { Token = HttpUtility.UrlEncode(Encrypt(decryptedToken)) });
  }
}

View (assuming you have jQuery)

$(function() {    
  $.get("https://site2.com/Impersonate/Start?token=@Html.Raw(Model.Token)");
});

So right after you log-in to Site1 you serve view that uses AJAX to send request to Site2 that will authenticate user also there. It is usually better idea to do it on request - the form authentication cookie for Site2 will eventually expire. So I'd favor something like like this on Site1:

<a href="/Login/StartImpersonation">Continue to site 2</a>

And

[HttpGet]
[Authorize]
public ActionResult StartImpersonation()
{
  // this is essentially similar to Login action 
  string encryptedToken = "";
  string redirectUrl = string.Format(CultureInfo.InvariantCulture,
    "https://site2.com/Impersonate/Start?encryptedToken={0}",
    HttpUtility.UrlEncode(encryptedToken));
  return Redirect(redirectUrl);
}

Which is better because a) cookie on Site2 can't expire b) if there is an error in impersonation user will see why (if there is an error in AJAX impersonation you can show some error to user, but it will look weird - authentication to site 2 haven't succeeded - why they're trying to authenticate me there ? :).

You want a single-sign-on (SSO) solution. This may be done any number of ways. OpenID is popular: https://en.wikipedia.org/wiki/OpenID This goes into plenty of details on a slightly older approach: http://www.codeproject.com/Articles/114484/Single-Sign-On-SSO-for-cross-domain-ASP-NET-appl Even more stuff here: C# ASP.NET Single Sign-On Implementation

HTH

On the link that would take someone from one site to the other, here's some of what you could put in the JS in a few places that may do what you want:

  1. On clicking the link, a $.get is done to grab the HTML of the log-in page.
  2. Then put into JS variables the login and password of the user for the second site's security into that HTML.
  3. Post the data through a $.ajax request so that the person is logged in through the JS behind the scenes.
  4. Now, either redirect in the current window or open a new window with the other site's home page and voila they are signed in without having to do any extra lifting if their own.

Note that some of this could be done earlier if you want to make the transition easier as when the page with the link loads, this could be done in the JS when the document is ready. The key point here is to have the cookies required for the authentication on the second site done without the user having to do any extra clicks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM