ASP.NET MVC - Đặt IIdentity hoặc IPrincipal tùy chỉnh


650

Tôi cần phải làm một cái gì đó khá đơn giản: trong ứng dụng ASP.NET MVC của tôi, tôi muốn đặt IIdentity / IPrincipal tùy chỉnh. Cái nào dễ hơn / phù hợp hơn. Tôi muốn mở rộng mặc định để tôi có thể gọi một cái gì đó như User.Identity.IdUser.Identity.Role. Không có gì lạ mắt, chỉ là một số thuộc tính bổ sung.

Tôi đã đọc hàng tấn bài báo và câu hỏi nhưng tôi cảm thấy như mình đang làm cho nó khó hơn thực tế. Tôi nghĩ rằng nó sẽ dễ dàng. Nếu người dùng đăng nhập, tôi muốn đặt IIdentity tùy chỉnh. Vì vậy, tôi nghĩ rằng, tôi sẽ thực hiện Application_PostAuthenticateRequesttrong global.asax của tôi. Tuy nhiên, điều đó được gọi theo mọi yêu cầu và tôi không muốn thực hiện cuộc gọi đến cơ sở dữ liệu theo mọi yêu cầu sẽ yêu cầu tất cả dữ liệu từ cơ sở dữ liệu và đặt vào một đối tượng IPrincipal tùy chỉnh. Điều đó cũng có vẻ rất không cần thiết, chậm và ở sai vị trí (thực hiện các cuộc gọi cơ sở dữ liệu ở đó) nhưng tôi có thể sai. Hoặc dữ liệu đó đến từ đâu?

Vì vậy, tôi nghĩ rằng, bất cứ khi nào người dùng đăng nhập, tôi có thể thêm một số biến cần thiết trong phiên của mình, mà tôi thêm vào IIdentity tùy chỉnh trong Application_PostAuthenticateRequesttrình xử lý sự kiện. Tuy nhiên, tôi Context.Sessionnullcó, do đó cũng không phải là con đường để đi.

Tôi đã làm việc này được một ngày rồi và tôi cảm thấy mình đang thiếu thứ gì đó. Điều này không quá khó để làm, phải không? Tôi cũng có một chút bối rối bởi tất cả những thứ liên quan (bán) đi kèm với điều này. MembershipProvider, MembershipUser, RoleProvider, ProfileProvider, IPrincipal, IIdentity, FormsAuthentication.... Am Tôi chỉ là người tìm thấy tất cả điều này rất khó hiểu?

Nếu ai đó có thể cho tôi biết một giải pháp đơn giản, thanh lịch và hiệu quả để lưu trữ một số dữ liệu bổ sung trên IIdentity mà không cần tất cả các fuzz thêm .. điều đó sẽ rất tuyệt! Tôi biết có những câu hỏi tương tự về SO nhưng nếu câu trả lời tôi cần có trong đó, tôi phải bỏ qua.


1
Xin chào Domi, đây là sự kết hợp của việc chỉ lưu trữ dữ liệu không bao giờ thay đổi (như ID người dùng) hoặc cập nhật cookie trực tiếp sau khi người dùng thay đổi dữ liệu phải được phản ánh trong cookie ngay lập tức. Nếu người dùng làm điều đó, tôi chỉ cần cập nhật cookie với dữ liệu mới. Nhưng tôi cố gắng không lưu trữ dữ liệu thay đổi thường xuyên.
Razzie

26
Câu hỏi này có 36k lượt xem và nhiều lượt upvote. đây có thực sự là một yêu cầu phổ biến không - và nếu vậy thì không có cách nào tốt hơn tất cả những thứ 'tùy chỉnh' này?
Simon_Weaver

2
@Simon_Weaver Có ASP.NET Identity biết, hỗ trợ thêm thông tin tùy chỉnh trong cookie được mã hóa dễ dàng hơn.
John

1
Tôi đồng ý với bạn, có đến nhiều thông tin như bạn đã đăng: MemberShip..., Principal, Identity. ASP.NET nên làm điều này dễ dàng hơn, đơn giản hơn và nhiều nhất là hai cách tiếp cận để xử lý xác thực.
băng thông rộng

1
@Simon_Weaver Điều này cho thấy rõ nhu cầu về hệ thống nhận dạng linh hoạt đơn giản dễ dàng hơn IMHO.
niico

Câu trả lời:


838

Đây là cách tôi làm điều đó.

Tôi quyết định sử dụng IPrincipal thay vì IIdentity vì điều đó có nghĩa là tôi không phải thực hiện cả IIdentity và IPrincipal.

  1. Tạo giao diện

    interface ICustomPrincipal : IPrincipal
    {
        int Id { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
    }
  2. CustomPrincipal

    public class CustomPrincipal : ICustomPrincipal
    {
        public IIdentity Identity { get; private set; }
        public bool IsInRole(string role) { return false; }
    
        public CustomPrincipal(string email)
        {
            this.Identity = new GenericIdentity(email);
        }
    
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  3. CustomPrincipalSerializeModel - để tuần tự hóa thông tin tùy chỉnh vào trường userdata trong đối tượng FormsAuthenticationTicket.

    public class CustomPrincipalSerializeModel
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  4. Phương thức đăng nhập - thiết lập cookie với thông tin tùy chỉnh

    if (Membership.ValidateUser(viewModel.Email, viewModel.Password))
    {
        var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
    
        CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
        serializeModel.Id = user.Id;
        serializeModel.FirstName = user.FirstName;
        serializeModel.LastName = user.LastName;
    
        JavaScriptSerializer serializer = new JavaScriptSerializer();
    
        string userData = serializer.Serialize(serializeModel);
    
        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                 1,
                 viewModel.Email,
                 DateTime.Now,
                 DateTime.Now.AddMinutes(15),
                 false,
                 userData);
    
        string encTicket = FormsAuthentication.Encrypt(authTicket);
        HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
        Response.Cookies.Add(faCookie);
    
        return RedirectToAction("Index", "Home");
    }
  5. Global.asax.cs - Đọc cookie và thay thế đối tượng HttpContext.User, điều này được thực hiện bằng cách ghi đè PostAuthenticateRequest

    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    
        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    
            JavaScriptSerializer serializer = new JavaScriptSerializer();
    
            CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
    
            CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
            newUser.Id = serializeModel.Id;
            newUser.FirstName = serializeModel.FirstName;
            newUser.LastName = serializeModel.LastName;
    
            HttpContext.Current.User = newUser;
        }
    }
  6. Truy cập trong chế độ xem Dao cạo

    @((User as CustomPrincipal).Id)
    @((User as CustomPrincipal).FirstName)
    @((User as CustomPrincipal).LastName)

và trong mã:

    (User as CustomPrincipal).Id
    (User as CustomPrincipal).FirstName
    (User as CustomPrincipal).LastName

Tôi nghĩ rằng mã là tự giải thích. Nếu không, hãy cho tôi biết.

Ngoài ra, để truy cập dễ dàng hơn nữa, bạn có thể tạo bộ điều khiển cơ bản và ghi đè đối tượng Người dùng được trả lại (HttpContext.User):

public class BaseController : Controller
{
    protected virtual new CustomPrincipal User
    {
        get { return HttpContext.User as CustomPrincipal; }
    }
}

và sau đó, cho mỗi bộ điều khiển:

public class AccountController : BaseController
{
    // ...
}

sẽ cho phép bạn truy cập các trường tùy chỉnh trong mã như thế này:

User.Id
User.FirstName
User.LastName

Nhưng điều này sẽ không hoạt động trong quan điểm. Vì vậy, bạn sẽ cần phải tạo một triển khai WebViewPage tùy chỉnh:

public abstract class BaseViewPage : WebViewPage
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

Biến nó thành một loại trang mặc định trong Lượt xem / web.config:

<pages pageBaseType="Your.Namespace.BaseViewPage">
  <namespaces>
    <add namespace="System.Web.Mvc" />
    <add namespace="System.Web.Mvc.Ajax" />
    <add namespace="System.Web.Mvc.Html" />
    <add namespace="System.Web.Routing" />
  </namespaces>
</pages>

và trong chế độ xem, bạn có thể truy cập nó như thế này:

@User.FirstName
@User.LastName

9
Thực hiện tốt đẹp; coi chừng RoleManagerModule thay thế hiệu trưởng tùy chỉnh của bạn bằng RolePrincipal. Điều đó gây cho tôi rất nhiều nỗi đau - stackoverflow.com/questions/10742259/
Kẻ

9
ok Tôi đã tìm thấy giải pháp, chỉ cần thêm một công tắc khác vượt qua "" (chuỗi trống) là email và Danh tính sẽ ẩn danh.
Pierre-Alain Vigete

3
DateTime.Now.AddMinutes (N) ... làm thế nào để làm điều này để nó không đăng xuất người dùng sau N phút, người dùng đã đăng nhập có thể được duy trì (ví dụ: khi người dùng kiểm tra 'Ghi nhớ tôi')?
1110

4
Nếu bạn đang sử dụng WebApiController, bạn sẽ cần phải thiết lập Thread.CurrentPrincipaltại Application_PostAuthenticateRequestcho nó để làm việc vì nó không dựa vàoHttpContext.Current.User
Jonathan Levison

3
@AbhinavGujjar FormsAuthentication.SignOut();hoạt động tốt với tôi.
LukeP

109

Tôi không thể nói trực tiếp cho ASP.NET MVC, nhưng đối với ASP.NET Web Forms, mẹo là tạo một FormsAuthenticationTicketvà mã hóa nó thành cookie khi người dùng đã được xác thực. Bằng cách này, bạn chỉ phải gọi cơ sở dữ liệu một lần (hoặc AD hoặc bất cứ điều gì bạn đang sử dụng để thực hiện xác thực) và mỗi yêu cầu tiếp theo sẽ xác thực dựa trên vé được lưu trong cookie.

Một bài viết hay về điều này: http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html (liên kết bị hỏng)

Biên tập:

Vì liên kết ở trên bị hỏng, tôi muốn giới thiệu giải pháp của LukeP trong câu trả lời của anh ấy ở trên: https://stackoverflow.com/a/10524305 - Tôi cũng đề nghị thay đổi câu trả lời được chấp nhận thành câu trả lời đó.

Chỉnh sửa 2: Một thay thế cho liên kết bị hỏng: https://web.archive.org/web/20120422011422/http://ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html


Đến từ PHP, tôi luôn đặt thông tin như UserID và các phần khác cần thiết để cấp quyền truy cập hạn chế trong Phiên. Lưu trữ phía khách hàng làm tôi lo lắng, bạn có thể nhận xét tại sao điều đó sẽ không là vấn đề?
John Zumbrum

@JohnZ - bản thân vé được mã hóa trên máy chủ trước khi được gửi qua mạng, vì vậy không giống như khách hàng sẽ có quyền truy cập vào dữ liệu được lưu trữ trong vé. Lưu ý rằng ID phiên cũng được lưu trữ trong cookie, vì vậy nó không thực sự khác biệt lắm.
John Rasch

3
Nếu bạn ở đây, bạn nên xem giải pháp của
LukeP

2
Tôi luôn lo ngại về khả năng vượt quá kích thước cookie tối đa ( stackoverflow.com/questions/8706924/ mẹo ) với phương pháp này. Tôi có xu hướng sử dụng Cachenhư là một Sessionthay thế để giữ dữ liệu trên máy chủ. Bất cứ ai có thể cho tôi biết nếu đây là một cách tiếp cận thiếu sót?
Red Taz

2
Cách tiếp cận tốt đẹp. Một vấn đề tiềm ẩn với điều này là nếu đối tượng người dùng của bạn có nhiều hơn một vài thuộc tính (và đặc biệt là nếu có bất kỳ đối tượng lồng nhau nào), việc tạo cookie sẽ thất bại một cách im lặng khi giá trị được mã hóa vượt quá 4KB (bạn có thể nghĩ dễ dàng hơn nhiều). Nếu bạn chỉ lưu trữ dữ liệu chính thì không sao nhưng bạn vẫn phải nhấn DB cho phần còn lại. Một xem xét khác là "nâng cấp" dữ liệu cookie khi đối tượng người dùng có chữ ký hoặc logic thay đổi.
Geoffrey Hudik

63

Dưới đây là một ví dụ để hoàn thành công việc. bool isValid được thiết lập bằng cách xem xét một số kho lưu trữ dữ liệu (giả sử cơ sở dữ liệu người dùng của bạn). UserID chỉ là một ID tôi đang duy trì. Bạn có thể thêm thông tin quảng cáo như địa chỉ email vào dữ liệu người dùng.

protected void btnLogin_Click(object sender, EventArgs e)
{         
    //Hard Coded for the moment
    bool isValid=true;
    if (isValid) 
    {
         string userData = String.Empty;
         userData = userData + "UserID=" + userID;
         FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddMinutes(30), true, userData);
         string encTicket = FormsAuthentication.Encrypt(ticket);
         HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
         Response.Cookies.Add(faCookie);
         //And send the user where they were heading
         string redirectUrl = FormsAuthentication.GetRedirectUrl(username, false);
         Response.Redirect(redirectUrl);
     }
}

trong gaxbal asax, thêm đoạn mã sau để lấy lại thông tin của bạn

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Request.Cookies[
             FormsAuthentication.FormsCookieName];
    if(authCookie != null)
    {
        //Extract the forms authentication cookie
        FormsAuthenticationTicket authTicket = 
               FormsAuthentication.Decrypt(authCookie.Value);
        // Create an Identity object
        //CustomIdentity implements System.Web.Security.IIdentity
        CustomIdentity id = GetUserIdentity(authTicket.Name);
        //CustomPrincipal implements System.Web.Security.IPrincipal
        CustomPrincipal newUser = new CustomPrincipal();
        Context.User = newUser;
    }
}

Khi bạn sẽ sử dụng thông tin sau, bạn có thể truy cập hiệu trưởng tùy chỉnh của mình như sau.

(CustomPrincipal)this.User
or 
(CustomPrincipal)this.Context.User

điều này sẽ cho phép bạn truy cập thông tin người dùng tùy chỉnh.


2
FYI - đó là Request.Cookies [] (số nhiều)
Dan Esparza

10
Đừng quên đặt Thread.CienPrincipal cũng như Context.User thành CustomPrincipal.
Nga Cam

6
GetUserIdentity () đến từ đâu?
Ryan

Như tôi đã đề cập trong bình luận, nó cung cấp cho việc triển khai System.Web.Security.IIdentity. Google về giao diện đó
Sriwantha Attanayake

16

MVC cung cấp cho bạn phương thức OnAuthorize treo từ các lớp trình điều khiển của bạn. Hoặc, bạn có thể sử dụng bộ lọc hành động tùy chỉnh để thực hiện ủy quyền. MVC làm cho nó khá dễ dàng để làm. Tôi đã đăng một bài blog về điều này ở đây. http://www.bradygaster.com/post/custom-authentication-with-mvc-3.0


Nhưng phiên có thể bị mất và người dùng vẫn xác thực. Không
Dragouf

@brady gaster, tôi đã đọc bài đăng trên blog của bạn (cảm ơn!), Tại sao ai đó sẽ sử dụng ghi đè "OnAuthorize ()" như được đề cập trên bài đăng của bạn trên mục global.asax "... AuthenticicateRequest (..)" được đề cập bởi người khác câu trả lời? Là một ưu tiên hơn người khác trong việc thiết lập người dùng nguyên tắc?
RayLovless

10

Đây là một giải pháp nếu bạn cần kết nối một số phương thức với @User để sử dụng trong chế độ xem của mình. Không có giải pháp cho bất kỳ tùy chỉnh thành viên nghiêm túc nào, nhưng nếu câu hỏi ban đầu là cần thiết cho lượt xem thì điều này có lẽ là đủ. Dưới đây được sử dụng để kiểm tra một biến được trả về từ một Authorizefilter, được sử dụng để xác minh xem một số liên kết có được trình bày hay không (không phải cho bất kỳ loại logic ủy quyền hoặc cấp quyền truy cập nào).

using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Security.Principal;

    namespace SomeSite.Web.Helpers
    {
        public static class UserHelpers
        {
            public static bool IsEditor(this IPrincipal user)
            {
                return null; //Do some stuff
            }
        }
    }

Sau đó, chỉ cần thêm một tham chiếu trong các khu vực web.config và gọi nó như dưới đây trong chế độ xem.

@User.IsEditor()

1
Trong giải pháp của bạn, chúng tôi lại cần thực hiện các cuộc gọi cơ sở dữ liệu mỗi lần. Bởi vì đối tượng người dùng không có thuộc tính tùy chỉnh. Nó chỉ có Tên và IsAuthanticated
oneNiceFriend

Điều đó phụ thuộc hoàn toàn vào việc thực hiện và hành vi mong muốn của bạn. Mẫu của tôi chứa 0 dòng cơ sở dữ liệu, hoặc vai trò, logic. Nếu tôi sử dụng IsInRole, nó có thể được lưu vào bộ nhớ cache trong cookie. Hoặc bạn thực hiện logic bộ nhớ đệm của riêng bạn.
Cơ sở

3

Dựa trên câu trả lời của LukeP và thêm một số phương pháp để thiết lập timeoutrequireSSLhợp tác với Web.config.

Các liên kết tham khảo

Mã sửa đổi của LukeP

1, Đặt timeoutdựa trên Web.Config. Các FormsAuthentication.Timeout sẽ nhận được giá trị thời gian chờ, được định nghĩa trong web.config. Tôi gói các mục sau đây là một hàm, trả ticketvề.

int version = 1;
DateTime now = DateTime.Now;

// respect to the `timeout` in Web.config.
TimeSpan timeout = FormsAuthentication.Timeout;
DateTime expire = now.Add(timeout);
bool isPersist = false;

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
     version,          
     name,
     now,
     expire,
     isPersist,
     userData);

2, Định cấu hình cookie có an toàn hay không, dựa trên RequireSSLcấu hình.

HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
// respect to `RequreSSL` in `Web.Config`
bool bSSL = FormsAuthentication.RequireSSL;
faCookie.Secure = bSSL;

3

Được rồi, vì vậy tôi là một nhà mật mã nghiêm túc ở đây bằng cách kéo lên câu hỏi rất cũ này, nhưng có một cách tiếp cận đơn giản hơn nhiều, điều này đã được @Baserz nói đến. Và đó là sử dụng kết hợp các phương thức mở rộng C # và bộ nhớ đệm (KHÔNG sử dụng phiên).

Trên thực tế, Microsoft đã cung cấp một số phần mở rộng như vậy trong Microsoft.AspNet.Identity.IdentityExtensionskhông gian tên. Chẳng hạn, GetUserId()là một phương thức mở rộng trả về Id người dùng. Ngoài ra còn có GetUserName()FindFirstValue()trả về các khiếu nại dựa trên IPrincipal.

Vì vậy, bạn chỉ cần bao gồm không gian tên, sau đó gọi User.Identity.GetUserName()để lấy tên người dùng được cấu hình bởi ASP.NET Identity.

Tôi không chắc chắn nếu điều này được lưu trong bộ nhớ cache, vì ASP.NET Identity cũ không được mở nguồn và tôi không bận tâm đến việc thiết kế ngược lại. Tuy nhiên, nếu không thì bạn có thể viết phương thức tiện ích mở rộng của riêng mình, điều đó sẽ lưu kết quả này trong một khoảng thời gian cụ thể.


Tại sao "không sử dụng phiên"?
Alex

@jitbit - vì phiên không đáng tin cậy và không an toàn. Vì lý do tương tự, bạn không bao giờ nên sử dụng phiên cho mục đích bảo mật.
Erik Funkenbusch

"Không đáng tin cậy" có thể được giải quyết bằng cách lặp lại phiên (nếu trống). "Không an toàn" - có nhiều cách để bảo vệ khỏi việc chiếm quyền điều khiển phiên (bằng cách sử dụng chỉ HTTPS + các cách khác). Nhưng tôi thực sự đồng ý với bạn. Bạn sẽ lưu nó ở đâu? Thông tin như thế IsUserAdministratorhay UserEmailvv? Bạn đang suy nghĩ HttpRuntime.Cache?
Alex

@jitbit - Đó là một tùy chọn hoặc giải pháp bộ đệm khác nếu bạn có. Đảm bảo hết hạn mục nhập bộ đệm sau một khoảng thời gian. Không an toàn cũng áp dụng cho hệ thống cục bộ, vì bạn có thể tự thay đổi cookie và đoán ID phiên. Người đàn ông ở giữa không phải là mối quan tâm duy nhất.
Erik Funkenbusch

2

Là một bổ sung cho mã LukeP cho người dùng Biểu mẫu web (không phải MVC) nếu bạn muốn đơn giản hóa quyền truy cập trong mã phía sau các trang của mình, chỉ cần thêm mã bên dưới vào trang cơ sở và lấy trang cơ sở trong tất cả các trang của bạn:

Public Overridable Shadows ReadOnly Property User() As CustomPrincipal
    Get
        Return DirectCast(MyBase.User, CustomPrincipal)
    End Get
End Property

Vì vậy, trong mã của bạn phía sau bạn có thể chỉ cần truy cập:

User.FirstName or User.LastName

Điều tôi thiếu trong một kịch bản Mẫu Web, là làm thế nào để có được hành vi tương tự trong mã không bị ràng buộc với trang, ví dụ như trong httpmodules tôi có nên luôn thêm một diễn viên trong mỗi lớp hay có cách nào thông minh hơn để có được điều này?

Cảm ơn câu trả lời và bạn cảm ơn đến LukeP kể từ khi tôi sử dụng ví dụ của bạn như một cơ sở cho người sử dụng tùy chỉnh của tôi (hiện tại có User.Roles, User.Tasks, User.HasPath(int), User.Settings.Timeoutvà nhiều thứ khác đẹp)


0

Tôi đã thử giải pháp được đề xuất bởi LukeP và thấy rằng nó không hỗ trợ thuộc tính Authorize. Vì vậy, tôi đã sửa đổi nó một chút.

public class UserExBusinessInfo
{
    public int BusinessID { get; set; }
    public string Name { get; set; }
}

public class UserExInfo
{
    public IEnumerable<UserExBusinessInfo> BusinessInfo { get; set; }
    public int? CurrentBusinessID { get; set; }
}

public class PrincipalEx : ClaimsPrincipal
{
    private readonly UserExInfo userExInfo;
    public UserExInfo UserExInfo => userExInfo;

    public PrincipalEx(IPrincipal baseModel, UserExInfo userExInfo)
        : base(baseModel)
    {
        this.userExInfo = userExInfo;
    }
}

public class PrincipalExSerializeModel
{
    public UserExInfo UserExInfo { get; set; }
}

public static class IPrincipalHelpers
{
    public static UserExInfo ExInfo(this IPrincipal @this) => (@this as PrincipalEx)?.UserExInfo;
}


    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginModel details, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            AppUser user = await UserManager.FindAsync(details.Name, details.Password);

            if (user == null)
            {
                ModelState.AddModelError("", "Invalid name or password.");
            }
            else
            {
                ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
                AuthManager.SignOut();
                AuthManager.SignIn(new AuthenticationProperties { IsPersistent = false }, ident);

                user.LastLoginDate = DateTime.UtcNow;
                await UserManager.UpdateAsync(user);

                PrincipalExSerializeModel serializeModel = new PrincipalExSerializeModel();
                serializeModel.UserExInfo = new UserExInfo()
                {
                    BusinessInfo = await
                        db.Businesses
                        .Where(b => user.Id.Equals(b.AspNetUserID))
                        .Select(b => new UserExBusinessInfo { BusinessID = b.BusinessID, Name = b.Name })
                        .ToListAsync()
                };

                JavaScriptSerializer serializer = new JavaScriptSerializer();

                string userData = serializer.Serialize(serializeModel);

                FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                         1,
                         details.Name,
                         DateTime.Now,
                         DateTime.Now.AddMinutes(15),
                         false,
                         userData);

                string encTicket = FormsAuthentication.Encrypt(authTicket);
                HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
                Response.Cookies.Add(faCookie);

                return RedirectToLocal(returnUrl);
            }
        }
        return View(details);
    }

Và cuối cùng trong Global.asax.cs

    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];

        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            PrincipalExSerializeModel serializeModel = serializer.Deserialize<PrincipalExSerializeModel>(authTicket.UserData);
            PrincipalEx newUser = new PrincipalEx(HttpContext.Current.User, serializeModel.UserExInfo);
            HttpContext.Current.User = newUser;
        }
    }

Bây giờ tôi có thể truy cập dữ liệu trong chế độ xem và bộ điều khiển chỉ bằng cách gọi

User.ExInfo()

Để đăng xuất tôi chỉ cần gọi

AuthManager.SignOut();

AuthManager ở đâu

HttpContext.GetOwinContext().Authentication
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.