わかりにくいmvc 5 Webアプリケーションで奇妙な問題が発生しています。アプリケーションは私の組織のために構築した内部Webアプリケーションです。主に、ドメインに接続されたコンピュータを使用する従業員がアクセスしますが、モバイルデバイスやタブレットを介してアクセスします。私は前者にwindows authとADを使って自動ログイン体験を提供したかったのです(すでにドメインにサインインしていれば、資格情報を入力する必要はありません)。また、他のすべてのユーザーに、ブラウザのネイティブプロンプト。これを実装するために、Windowsユーザーを認証し、暗号化されたCookieをユーザーの役割を持つメインアプリケーションに戻す別のWebアプリケーションを作成しました。非ウィンドウベースのブラウザには、メインアプリケーションにログインページが表示され、ADに対して認証され、ユーザーの役割が取得されます。ログインの種類ごとに、ロールはクレームに変換されず、ユーザーのためにフェデレーションされたトークンが作成されます。 私の問題は、ユーザーがWindows認証アプリケーションへのリダイレクトを介してログインすると、奇妙な問題が発生していることです。標準のフォーム提出であろうと、AJAXの投稿であろうと、私が提出するフォームは、ページをロードする1分以内に提出されなければならない。そうでなければコントローラアクションに送られるパラメータはバインドされない(ヌル)。ユーザーがカスタムログインページ経由でログインした場合、この問題は存在しません。ここでフォームがアイドル状態のときにバインドされないASP.NET MVCアクションパラメータ
は、Global.asaxの中で最初の認証を実行するコードである:ここでは
Protected Sub Application_AuthenticateRequest()
Dim user As System.Security.Principal.IPrincipal = HttpContext.Current.User
If user Is Nothing Then
'First check if an authentication cookie is has been generated from the windows login
'authentication app
Dim authCookie As HttpCookie = Request.Cookies(".ConnectAUTH")
If Not authCookie Is Nothing Then
' Extract the roles from the cookie, and assign to our current principal, which is attached to the HttpContext.
Dim ticket As FormsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value)
Dim claims As New List(Of Claim)
For Each role In ticket.UserData.Split(";"c)
claims.Add(New Claim(ClaimTypes.Role, role))
Next
Dim claimIdent As New ClaimsIdentity(claims, "Custom")
claimIdent.AddClaim(New Claim(ClaimTypes.WindowsAccountName, ticket.Name))
claimIdent.AddClaim(New Claim(ClaimTypes.NameIdentifier, ticket.Name))
Dim claimPrinc As New ClaimsPrincipal(claimIdent)
Dim token = New SessionSecurityToken(claimPrinc)
Dim sam = FederatedAuthentication.SessionAuthenticationModule
sam.WriteSessionTokenToCookie(token)
HttpContext.Current.User = New ClaimsPrincipal(claimIdent)
Return
Else 'User hasn't been authenticated
Dim ConnectBaseURL = Request.Url.GetLeftPart(UriPartial.Authority) & "/"
Dim mvcPath As String = Request.Url.ToString.Replace(ConnectBaseURL, "")
'If user is requesting the login page then let them authenticate through there
If mvcPath.ToUpper.Contains("ACCOUNT/LOGIN") Or mvcPath.ToUpper.Contains("ACCOUNT/LOGUSERIN") Or mvcPath.ToUpper.Contains("SIGNALR") Then Exit Sub
'for brevity i will omit the code below:
' Basically it checks whether the browser is windows based if so then it redirects the user to
' a windows login authenticator which authenticates the user against Active Directory, builds and sends
' an encrypted cookie with a list of roles/groups that the user belongs to. When this function detects that cookie
' it decrypts it, sets up a claims identity, add the user roles and creates a federated authentication token
'If the the browser is not windows based then it redirects the user to a custom login page which is tied to an MVC
'action that will also authenticate the user against active directory and and set up the claims identity ...
End If
End If
End Sub
は、彼らがカスタムログインページにリダイレクトされている場合は、ユーザーを認証コードです:
<AllowAnonymous>
<HttpPost>
<ValidateAntiForgeryToken>
<OutputCache(NoStore:=True, Duration:=0, Location:=OutputCacheLocation.None, VaryByParam:="None")>
Public Function LogUserIn(model As User, returnURL As String) As ActionResult
Try
If ModelState.IsValid Then
If Membership.ValidateUser(model.UserName, model.PassWord) Then
'Call helper function to get all user roles and convert them to claims
Dim userClaims As List(Of Claim) = New LDAPHelper().GetUserGroups(model.UserName)
userClaims.Add(New Claim(ClaimTypes.WindowsAccountName, model.UserName))
userClaims.Add(New Claim(ClaimTypes.NameIdentifier, model.UserName))
userClaims.Add(New Claim(ClaimTypes.Name, model.UserName))
Dim claimIdent As New ClaimsIdentity(userClaims, "Custom")
Dim claimPrinc As New ClaimsPrincipal(claimIdent)
Dim token = New SessionSecurityToken(claimPrinc)
Dim sam = FederatedAuthentication.SessionAuthenticationModule
sam.WriteSessionTokenToCookie(token)
If returnURL Is Nothing Then
Return Redirect("~/")
Else
Return Redirect(returnURL)
End If
Else
ModelState.AddModelError("LoginFailure", "The username/password combination was invalid")
End If
End If
Return Nothing
Catch ex As Exception
ModelState.AddModelError("LoginFailure", ex.Message)
Return Nothing
End Try
End Function
私はフォームのクッキーをWindowsの認証アプリケーションから送信せず、メインアプリケーションにリダイレクトされた後、クレームとトークンの作成をハードコードすることで、方程式からクッキーを削除しようとしました。 HttpContext.Current.Userオブジェクトは、Application_AuthenticateRequestがヒットするたびに有効なClaimPrincipalとして設定されたままです。私はカスタムAuthorizeAttributeを実装しており、ユーザーは常に認証され、承認されています。面白いのは、パラメータがnullとして渡された直後に、フォームのSubmitボタンをもう一度押すと動作するということです。私は同様の問題のためにオンラインで精査しました - 何も - 私はここに誰かがアイデアを持っていることを望んでいます。
アイデアのためにWillyさんにお礼を言いますが、セッション認証トークンを使用する場合は、リクエストごとにプリンシパルを設定する必要はありません。ユーザーがログインして認証されると、クレームID /プリンシパルを使用してセッショントークンが作成され、トークンが無効になるかログアウトするまで設定されたままになります。コントローラの動作を確認して、ユーザーIDがまだ設定されているが、アクションに送信されたパラメータがnullであることを確認する。 – PlasmaX