MVC 5 AccessクレームIDユーザーデータ


119

Entity Framework 5 Database Firstアプローチを使用してMVC 5 Webアプリケーションを開発しています。ユーザーの認証にOWINを使用しています。以下は、私のアカウントコントローラー内の私のログインメソッドを示しています。

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);
}

ご覧のとおり、ClaimsIdentityを作成し、それにいくつかのクレームを追加してから、AuthenticationManagerを使用してOWINに渡し、サインインを実行しています。

私が抱えている問題は、コントローラーまたはRazorビューで、アプリケーションの残りの部分のクレームにアクセスする方法がわからないことです。

このチュートリアルに記載されているアプローチを試しました

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

たとえば、クレームに渡された値にアクセスするために、コントローラーコードでこれを試しましたが、user.Claimsはnullに等しいです。

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

おそらく私はここで何かを見逃している。

更新

ダリンの答えに基づいて、私は彼のコードを追加しましたが、それでもクレームへのアクセスを確認できません。identity.Claimsの上にマウスを置いたときに表示されるものを示す以下のスクリーンショットを参照してください。

ここに画像の説明を入力してください


クッキーがブラウザから送り返されたことを確認できますか?たぶんあなたのセキュリティ設定はSSLを要求しますか?
最小特権2014年

@leastprivilegeありがとうございます。これから調べます。Stackoverflow、stackoverflow.com / questions / 20319118 /…でこの質問を見つけました。これは私が抱えている問題とまったく同じですが、残念ながら答えはありません:(
tcode

OWINコンポーネントはどのように初期化されますか?
Derek Van Cuyk 2014

私は最近このような問題を抱えていました。:私は、このソリューションが役に立てば幸いstackoverflow.com/questions/34537475/...
アレクサンドル・

回答:


172

これを試して:

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

ご協力いただきありがとうございます。コントローラ内のアクションで提案された回答を使用してClaims値にアクセスしようとしましたが、Identity.ClaimsはまだNULLです(スクリーンショット付きの更新された質問を参照)。他のアイデアはありますか?私はあなたの助けに感謝します。
tcode

いいえ、他のアイデアはありません。これは常に私のために働いてきました。
Darin Dimitrov 2014年

最後の質問です。上記のコードが機能する前に、このdotnetcodr.com/2013/02/25/…のように、Global.asaxに独自のカスタムClaimsAuthenticationManagerクラスとApplication_PostAuthenticateRequest()を作成する必要がありますか?再度、感謝します。
tcode

7
初めて承認するまでは、ログイン方法が完了するまでこれにアクセスできません。そのため、OPはその時点で表示しません。Loginメソッドで必要な場合は、この時点で手動でロードする必要があります。
Adam Tuliper-MSFT 2014年

私はasp.netコアで作業していて、2時間以上の間にLinkedInプロフィール写真を取得する方法を探しています。行き詰まっている、疲れている、あなたの答えが見つかるまで諦めたい。100万回ありがとうと言いたい... +1
Vayne

36

これを行うこともできます:

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

更新

コメントに従ってさらに説明を提供します。

次のようにシステム内にユーザーを作成する場合:

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

IDに関連するいくつかのクレームが自動的に入力されているはずです。

ユーザー認証後にカスタマイズされたクレームを追加するには、次のようにします。

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

主張は、ダーリンが上記で回答したように、または私がそうであるように、読み返すことができます。

IDを渡して以下を呼び出すと、クレームは永続化されます。

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

おかげで、それでもまだうまくいきません。私の更新された質問を見ることができますか?また、最後の質問です。上記のコードが機能する前に、このdotnetcodr.com/2013/02/25/…のように、Global.asaxに独自のカスタムClaimsAuthenticationManagerクラスとApplication_PostAuthenticateRequest()を作成する必要がありますか?ご協力いただきありがとうございます。
tcode

こんにちは、PCに戻ったときに見てみましょう。
ハチノイド2014年

ありがとう、本当に感謝しています。これが私を取り締まり始めた段階で:)
tcode

@tgriffithsこんにちは。更新情報を追加しました。うまくいけば、もう少し情報を提供します。幸運を。:)
ハチノイド2014年

残念ながら、UserManagerなどの組み込みのEntity Framework Code Firstを使用していません。乾杯。
tcode

30

必要なものを確認するために独自の拡張クラスを作成するので、コントローラーまたはビューに必要な場合は、次のような名前空間にusingを追加するだけです。

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 ....
    {
      .....
    }
}

私のコントローラーでは:

using XXX.CodeHelpers.Extended;

var claimAddress = User.GetAddress();

私のかみそりで:

@using DinexWebSeller.CodeHelpers.Extended;

@User.GetFullName()

8
return claim?.Value;なぜそうでないのか
Halter

17

これは、クレームを常に使用したくない場合の代替手段です。Ben Fosterによるこのチュートリアルをご覧ください

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

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

}

次に、ベースコントローラーを追加できます。

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

あなたのコントローラーでは、次のようにします:

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

12

Darinの答えにさらに触れるには、FindFirstメソッドを使用して特定のクレームに到達できます。

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

または、これも文字列myValue = identity.FindFirstValue( "MyClaimType");です。
ファンカルロスプエルト

FindFirstが「ロール」タイプのクレームを見つけられない場合はどうなりますか?null例外?
フィル

10

これもできます。

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

8

IEnumerableをクエリするには、system.linqを参照する必要があることに注意してください。
これはあなたに必要な拡張オブジェクトを提供します:

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

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

ただし、特にStartup.Auth.csでregenerateIdentityが有効になっている場合は、「GenerateUserIdentityAsync」メソッド内にクレームを追加することをお勧めします。


これGenerateUserIdentityAsyncは素晴らしい提案でした。私は完全に見落としました。バジルに感謝します。
timmi4sa 2014年

6

@Rosdi Kasimの最短で簡略化されたバージョンの答えは

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

Claimname 取得するクレームです。つまり、「StreedAddress」クレームを探している場合、上記の回答は次のようになります。

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

「claimvalue」の例を提供すると、時間を節約できます。ありがとう
Nour Lababidi

2

ControllerBaseクラスによれば、アクションを実行するユーザーのクレームを取得できます。

ここに画像の説明を入力してください

1行で実行する方法を次に示します。

var claims = User.Claims.ToList();


0

私はベースコントローラーでそのように使用しました。すぐに使えるように共有するだけです。

    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();
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.