0

わかりにくい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ボタンをもう一度押すと動作するということです。私は同様の問題のためにオンラインで精査しました - 何も - 私はここに誰かがアイデアを持っていることを望んでいます。

答えて

0

私の答えは完全に無関係かもしれませんが、私は助けを求めています。私たちは何か類似していた。 MVC4のWeb APIからMVC5に切り替えたとき。トークンをチェックしたAuthorizationAttributeがありました。私たちはそれを読んで、プリンシパルを設定しましたが、コントローラーのアクションに当たったときに、プリンシパルは消えました(mVC5ではこれが機能しました)。短いストーリーは、MVC5の非同期性と関連していなければならないということでした。私たちは、IAuthenticationFilter(mVC5がプリンシパルを設定することを期待している)を実装した別の属性を実装する方法を変更しました。 これはあなたと何が関係していますか? MVC5 が、にプリンシパル(Application_AuthenticateRequest かもしれないは場所ではない)を設定すると予想されるイベントを調べる必要があります。間違ったスレッドに設定されている可能性があり、コントローラに到着したときに消えてしまうことがあります。

+1

アイデアのためにWillyさんにお礼を言いますが、セッション認証トークンを使用する場合は、リクエストごとにプリンシパルを設定する必要はありません。ユーザーがログインして認証されると、クレームID /プリンシパルを使用してセッショントークンが作成され、トークンが無効になるかログアウトするまで設定されたままになります。コントローラの動作を確認して、ユーザーIDがまだ設定されているが、アクションに送信されたパラメータがnullであることを確認する。 – PlasmaX

関連する問題