MVC 5 Truy cập Khiếu nại Dữ liệu Danh tính Người dùng


119

Tôi đang phát triển ứng dụng web MVC 5 bằng cách sử dụng Phương pháp tiếp cận đầu tiên cơ sở dữ liệu Entity Framework 5 . Tôi đang sử dụng OWIN để xác thực Người dùng. Dưới đây hiển thị phương pháp Đăng nhập của tôi trong Bộ điều khiển tài khoản của tôi.

public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = _AccountService.VerifyPassword(model.UserName, model.Password, false);
        if (user != null)
        {
            var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, model.UserName), }, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);

            identity.AddClaim(new Claim(ClaimTypes.Role, "guest"));
            identity.AddClaim(new Claim(ClaimTypes.GivenName, "A Person"));
            identity.AddClaim(new Claim(ClaimTypes.Sid, user.userID)); //OK to store userID here?

            AuthenticationManager.SignIn(new AuthenticationProperties
            {
                IsPersistent = model.RememberMe
            }, identity);

            return RedirectToAction("Index", "MyDashboard");
        }
        else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }
    // If we got this far, something failed, redisplay form
    return View(model);
}

Như bạn có thể thấy, tôi đang tạo ClaimsIdentity và thêm một số xác nhận quyền sở hữu vào nó, sau đó chuyển nó tới OWIN bằng AuthenticationManager để thực hiện đăng nhập.

Vấn đề tôi đang gặp phải là tôi không chắc cách truy cập các xác nhận quyền sở hữu trong phần còn lại của ứng dụng của mình, trong Bộ điều khiển hoặc trong Chế độ xem Razor.

Tôi đã thử cách tiếp cận được liệt kê trong hướng dẫn này

http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/

Ví dụ: tôi đã thử điều này trong mã Bộ điều khiển của mình để cố gắng truy cập vào các giá trị được chuyển vào Yêu cầu, tuy nhiên, người dùng. Yêu cầu bằng null

var ctx = HttpContext.GetOwinContext();
ClaimsPrincipal user = ctx.Authentication.User;
IEnumerable<Claim> claims = user.Claims;

Có lẽ tôi đang thiếu một cái gì đó ở đây.

CẬP NHẬT

Dựa trên câu trả lời của Darin, tôi đã thêm mã của anh ấy nhưng tôi vẫn không thấy quyền truy cập vào Yêu cầu. Vui lòng xem ảnh chụp màn hình bên dưới cho biết những gì tôi thấy khi di chuột qua danh tính.

nhập mô tả hình ảnh ở đây


Bạn có thể xác nhận rằng cookie được gửi lại bởi trình duyệt không? Có thể cài đặt bảo mật của bạn yêu cầu SSL?
ít đặc quyền nhất

@leastprivilege Cảm ơn, tôi sẽ xem xét vấn đề đó ngay bây giờ. Tôi tìm thấy câu hỏi này trên Stackoverflow, stackoverflow.com/questions/20319118/... nó là cùng một vấn đề chính xác tôi đang gặp khó, nhưng tiếc là không có câu trả lời cho nó :(
tcode

Các thành phần OWIN của bạn được khởi tạo như thế nào?
Derek Van Cuyk

Gần đây tôi đã gặp một vấn đề như thế này; Tôi hy vọng giải pháp này sẽ hữu ích: stackoverflow.com/questions/34537475/…
Alexandru,

Câu trả lời:


172

Thử cái này:

[Authorize]
public ActionResult SomeAction()
{
    var identity = (ClaimsIdentity)User.Identity;
    IEnumerable<Claim> claims = identity.Claims;
    ...
}

Cảm ơn bạn đã giúp đỡ. Tôi đã sử dụng câu trả lời được đề xuất của bạn trong một Hành động trong Bộ điều khiển để thử và truy cập các giá trị Xác nhận quyền sở hữu, tuy nhiên, tôi nhận dạng được Yêu cầu bồi thường vẫn là NULL (xem câu hỏi cập nhật kèm theo ảnh chụp màn hình). Bất kỳ ý tưởng nào khác? Tôi đánh giá cao sự giúp đỡ của bạn.
tcode

Không, xin lỗi tôi không có ý kiến ​​khác. Điều này đã luôn luôn làm việc cho tôi.
Darin Dimitrov

Xin lỗi, một câu hỏi cuối cùng. Tôi có cần tạo lớp ClaimsAuthenticationManager tùy chỉnh của riêng mình và Application_PostAuthenticateRequest () trong Global.asax như dotnetcodr.com/2013/02/25/… trước khi mã ở trên của tôi hoạt động không? Cảm ơn một lần nữa.
tcode

7
Cho đến khi bạn Ủy quyền lần đầu tiên, bạn sẽ không có quyền truy cập vào điều này cho đến sau phương thức đăng nhập của bạn, đó là lý do tại sao OP không nhìn thấy nó tại thời điểm đó. Bạn phải tải thủ công tại thời điểm này nếu bạn muốn trong phương thức Đăng nhập.
Adam Tuliper - MSFT

Tôi đang làm việc với lõi asp.net và đang tìm cách lấy ảnh hồ sơ LinkedIn trong hơn 2 giờ. Tôi bế tắc, tôi mệt mỏi, tôi muốn bỏ cuộc cho đến khi tôi thấy câu trả lời của bạn. Tôi muốn nói lời cảm ơn triệu lần ... 1
Vayne

36

Bạn cũng có thể làm điều này:

//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
var claims = identity.Claims;

Cập nhật

Để cung cấp thêm lời giải thích theo ý kiến.

Nếu bạn đang tạo người dùng trong hệ thống của mình như sau:

UserManager<applicationuser> userManager = new UserManager<applicationuser>(new UserStore<applicationuser>(new SecurityContext()));
ClaimsIdentity identity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);

Bạn sẽ tự động có một số Tuyên bố liên quan đến Danh tính của bạn.

Để thêm xác nhận quyền sở hữu tùy chỉnh sau khi người dùng xác thực, bạn có thể làm như sau:

var user = userManager.Find(userName, password);
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));

Các tuyên bố có thể được đọc lại như Darin đã trả lời ở trên hoặc như tôi có.

Các xác nhận quyền sở hữu vẫn tồn tại khi bạn gọi bên dưới chuyển danh tính trong:

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = persistCookie }, identity);

Cảm ơn, nhưng điều này vẫn không hiệu quả với tôi. Bạn có thể xem câu hỏi cập nhật của tôi không? Ngoài ra, một câu hỏi cuối cùng. Tôi có cần tạo lớp ClaimsAuthenticationManager tùy chỉnh của riêng mình và Application_PostAuthenticateRequest () trong Global.asax như dotnetcodr.com/2013/02/25/… trước khi mã ở trên của tôi hoạt động không? Cảm ơn một lần nữa vì sự giúp đỡ của bạn.
tcode

Xin chào, tôi sẽ xem xét khi tôi sử dụng lại PC.
hutchonoid

cảm ơn, thực sự đánh giá cao nó. Tại một sân khấu nơi này đang bắt đầu để crack tôi :)
tcode

@tgriffiths Xin chào, tôi đã thêm một bản cập nhật cho bạn. Hy vọng cung cấp thêm một chút thông tin. Chúc may mắn. :)
hutchonoid

Rất tiếc, tôi không sử dụng Mã khung thực thể được tích hợp sẵn Đầu tiên, ví dụ: UserManager, v.v. Nhưng cảm ơn bạn đã đóng góp ý kiến. Chúc mừng.
tcode

30

Tôi tạo lớp mở rộng của riêng mình để xem những gì tôi cần, vì vậy khi tôi cần vào bộ điều khiển hoặc Chế độ xem của mình, tôi chỉ thêm cách sử dụng vào không gian tên của mình như sau:

public static class UserExtended
{
    public static string GetFullName(this IPrincipal user)
    {
        var claim = ((ClaimsIdentity)user.Identity).FindFirst(ClaimTypes.Name);
        return claim == null ? null : claim.Value;
    }
    public static string GetAddress(this IPrincipal user)
    {
        var claim = ((ClaimsIdentity)user.Identity).FindFirst(ClaimTypes.StreetAddress);
        return claim == null ? null : claim.Value;
    }
    public ....
    {
      .....
    }
}

Trong bộ điều khiển của tôi:

using XXX.CodeHelpers.Extended;

var claimAddress = User.GetAddress();

Trong dao cạo của tôi:

@using DinexWebSeller.CodeHelpers.Extended;

@User.GetFullName()

8
return claim?.Value;bởi vì tại sao không
Halter

17

Đây là một giải pháp thay thế nếu bạn không muốn sử dụng xác nhận quyền sở hữu mọi lúc. Hãy xem hướng dẫn này của Ben Foster.

public class AppUser : ClaimsPrincipal
{
    public AppUser(ClaimsPrincipal principal)
        : base(principal)
    {
    }

    public string Name
    {
        get
        {
            return this.FindFirst(ClaimTypes.Name).Value;
        } 
    }

}

Sau đó, bạn có thể thêm một bộ điều khiển cơ sở.

public abstract class AppController : Controller
{       
    public AppUser CurrentUser
    {
        get
        {
            return new AppUser(this.User as ClaimsPrincipal);
        }
    }
}

Trong bộ điều khiển của bạn, bạn sẽ làm:

public class HomeController : AppController
{
    public ActionResult Index()
    {
        ViewBag.Name = CurrentUser.Name;
        return View();
    }
}

12

Để tìm hiểu thêm về câu trả lời của Darin, bạn có thể đi đến các yêu cầu cụ thể của mình bằng cách sử dụng phương pháp FindFirst :

var identity = (ClaimsIdentity)User.Identity;
var role = identity.FindFirst(ClaimTypes.Role).Value;

Hoặc cái này quá string myValue = ID.FindFirstValue ("MyClaimType");
Juan Carlos Puerto

Điều gì sẽ xảy ra nếu FindFirst không tìm thấy bất kỳ xác nhận quyền sở hữu nào với loại "vai trò"? ngoại lệ null?
Phil

10

Bạn cũng có thể làm điều này.

IEnumerable<Claim> claims = ClaimsPrincipal.Current.Claims;

8

Hãy nhớ rằng để truy vấn IEnumerable, bạn cần tham chiếu system.linq.
Nó sẽ cung cấp cho bạn đối tượng mở rộng cần thiết để làm:

CaimsList.FirstOrDefault(x=>x.Type =="variableName").toString();

7

phiên bản ngắn nhất và đơn giản nhất của @Rosdi Kasim'd câu trả lời là

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("claimname").Value;

Claimname là xác nhận quyền sở hữu bạn muốn truy xuất, tức là nếu bạn đang tìm kiếm xác nhận quyền sở hữu "StreedAddress" thì câu trả lời ở trên sẽ như thế này

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("StreedAddress").Value;

cung cấp ví dụ "giá trị xác nhận quyền sở hữu" đã tiết kiệm thời gian của tôi. Cảm ơn bạn
Nour Lababidi

6
Request.GetOwinContext().Authentication.User.Claims

Tuy nhiên, tốt hơn là bạn nên thêm các xác nhận quyền sở hữu bên trong phương thức "GenerateUserIdentityAsync", đặc biệt là nếu kích hoạt ReoIdentity trong Startup.Auth.cs.


Đó GenerateUserIdentityAsynclà một gợi ý tuyệt vời, tôi đã hoàn toàn bỏ qua nó. Cảm ơn rất nhiều Basil.
timmi4sa

2

Theo lớp ControllerBase, bạn có thể nhận các xác nhận quyền sở hữu cho người dùng thực hiện hành động.

nhập mô tả hình ảnh ở đây

đây là cách bạn có thể làm điều đó trong 1 dòng.

var claims = User.Claims.ToList();


0

Tôi đã sử dụng nó như vậy trong bộ điều khiển cơ sở của mình. Chỉ cần chia sẻ để sẵn sàng sử dụng.

    public string GetCurrentUserEmail() {
        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;
        var email = claims.Where(c => c.Type == ClaimTypes.Email).ToList();
        return email[0].Value.ToString();
    }

    public string GetCurrentUserRole()
    {
        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;
        var role = claims.Where(c => c.Type == ClaimTypes.Role).ToList();
        return role[0].Value.ToString();
    }
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.