0

こんにちはすべて私は初心者のgrails/springセキュリティの質問があります。 grails 3プロジェクトではspring-security-oauth2-providerを使ってoauth2を設定しました.REST APIを保護するためにはうまくいくようです。grailsと既存のoauth2プロバイダで春のセキュリティを使用してフォームベースのログインを実装する方法

しかし、私たちはGSPを使って同じプロジェクトにWebフロントエンドを追加し始め、交差点に着きました。通常、oauth2は、エンドポイントへの認証とトークンの受信によって動作します。トークンは、保護されたリソースへのアクセスを維持するための後続の要求でHTTPヘッダーで使用できます。しかし、私のWebフロントエンドにはログインページがあります。だから当初は、Webフロントエンドをクライアントの1つとして扱うことにしました(私たちのiOSアプリには1クライアント、Androidアプリには1クライアントがあります。しかし、同じプロジェクト内にあるので、私たちのoauth2プロバイダーのエンドポイントに私たちのコントローラーコードから(ログイン用の)HTTP要求をするのは奇妙に思えます。私のWebフロントエンドが必要とするほとんどのリクエストは、基本的なサービスとドメインオブジェクトに直接アクセスしたいので、特別なホップを追加することは非生産的です。

コントローラのコードでlogin.gspを使用してログインすると、私はoauth2のログインを迂回して、私が使用しているUsernamePasswordAuthenticationTokenでauthenticationManager.authenticate()を使用してストレートスプリングのセキュリティ認証を行います。私のフォームに渡されたユーザー名とパスワードフィールドから構成し、次にレスポンスに対してSecurityContextHolder.getContext()。setAuthentication()を呼び出します。このような半分の問題は、this投稿から現状のスレッドでSecurityContextHolderを設定するだけで、フィルタチェーンの終わりでSecurityContextHolderがクリアされるので、後続のリクエストは認証されないという問題が解決されます。この認証が成功した場合(すなわち例外がスローされない場合)は、ユーザーオブジェクトをHTTPセッションに挿入し、その後のすべてのリクエストで、認証済みであることを「通知」する方法で取得しようとします。しかし、これはハッキーと汚れているようです。それは私のユーザオブジェクトがDBセッションに接続されていないことにつながります(遅延初期化の例外を引き起こします)。

thisのように、SecurityContext全体がHTTPセッションに置かれているが、後続の要求でそのSecurityContextを使用する方法を示していないような投稿から、同様の提案がありました。

私の究極の質問は、間違った方向に進むのでしょうか?私がしたいことを達成するためのより良い、よりクリーンな方法がありますか?私たちがこれをやろうとする最初の人になることはできないと思います。

答えて

0

私は自分自身の質問に答えることが少し悲しいです。しかし私は、私のソリューションがこの問題を解決する正しい方法かどうかを見たいと思っていました。

私たちがやったことは、フィルタを使用することでした。インターセプタはGrails 3に移行する方法でなければならないが、そこに達する前に、フィルタを備えた作業バージョンを用意したいと思う。

AuthController.signInメソッドでは、UsernamePasswordAuthenticationToken認証プロセスを実行し、実際にSecurityContextをHTTPセッションに移動します。ちょっとおもしろいことに、私は後でsession.setAttributeを明示的に行う必要なく、これが実際にすでに(SPRING_SECURITY_CONTEXTキーを使って)行われていることがわかりました。私の理論的根拠は、SecurityContextはUsernamePasswordAuthenticationTokenを使用してこの要求に対してのみ認証されるため、HTTPセッションでそれを保持して、後続の要求に対して再ロードできるようにする必要があるということです。私のフィルタでは、最初に順番に配置したので、HTTPセッションでSecurityContextをチェックし、その "認証"を現在のSecurityContextにコピーします。 HTTPセッションで何も見つからなかった場合、ユーザーをログインページにリダイレクトするために、最後に順番に配置されたフィルタも既に用意されていることに注意してください。

この変更で、コントローラ内のspringSecurityServiceにアクセスして、現在ログインしているユーザーにアクセスすることができました。また、GSPページにsec:ifAllGrantedを使用できるようにすることも含まれています。しかし、まだ何かが実行可能ではありません - 私たちは@Secured( "#oauth2.isUser()")注釈を使用してコントローラメソッドを保護することはできず、常に401を打つことはできません。認証を行うUsernamePasswordAuthenticationTokenを使用するのは依然として"完全な"認証が必要ですか?

セキュリティコンテキストの代わりにOAuth2アクセストークンをHTTPセッションに入れ、 "認証" HTTPヘッダーに "Bearer" + accessTokenを追加したフィルタをさらに試しました。これはうまく動作せず、予備のロギングでは、1つのHTTPリクエスト(ページビュー)で、フィルタに何度も入り、OAuth2アクセストークンを取得してリクエストのHTTPヘッダーに入れることが初めてであることがわかりました。

したがって、私は、フィルタを使用してセッションに接続したままにしておきたいと考えています。それとも、私はこれをやったのでしょうか? @Securedアノテーションでコントローラを保護するにはどうすればいいですか?

+0

を私は「shouldnもはや私自身の質問に再び答えていることに驚くことはありません。おそらくそれは答えがあまりにも明白だったか、あるいは誰もこれに遭遇しなかったかもしれないからです。いずれにせよ、私はちょうど誰かがこの有用性を見つけた場合に備えて、ここに私の旅を「ブログ」するつもりです。 私の質問に対する短い答えは、全くありません。それは絶対に不要です。 Spring Securityには多くのデフォルト/組み込み機能が用意されています。 コメントは最大600文字ですので、私は別の答えの形で私の付録を投稿しますが、私が与えられたすべてのスペースを使い果たす前に投稿します。 – paulito415

0

私はすでに答えを与えているので、この答えをどのように扱うのだろうかと思います。悲しいかな、本当に心配している - 私は最初に質問をした人です。

私が見たすべてのドキュメントでは、 Grails Security - Reference DocumentationSpring Security Core Plugin - Reference DocumentationGrails Spring Security Core Plugin Custom AuthenticationHow to customize spring security plugin Login page in grails私はSpring Security OAuth2プラグインを使用していましたが、Spring Security Core Plug-Inが提供するすべての機能も提供されていました。これは、フォームベースのログインがすぐにサポートされ、カスタマイズされたログインフォームもサポートされていることを意味します。

カスタムログインフォームでは、独自のAuthControllerのsignInメソッドをlogin.gspで呼び出す代わりに、$ {request()を使用してLoginController(Spring Securityプラグインに付属)の "authenticate" .contextPath}/login/authenticateを実行します。

私は実際にインタセプタを無効にした後に実際に試しましたが、リダイレクトループが発生してブラウザが救済されました。私たちには必要な設定がいくつかあると思います(チェーンマップやフィルターを使用して)、これはまだ動作しません。助け

ことの一つは、これは私のデバッグを支援するための情報をログに記録するの多くを与えたGrailsのアプリ/ confに/ logback.groovy

logger 'org.springframework.security', DEBUG, ['STDOUT'], false 
logger 'grails.plugin.springsecurity', DEBUG, ['STDOUT'], false 

に以下の2行を追加することでした。何らかの理由で、何かが認証されていないため、私の要求で匿名のトークンを何とか押し込んだことに気付きました。

デバッグに時間を費やした結果、答えがapplication.groovyにあることがわかりました。私が持っていた問題は、デフォルトですべてのアプリケーションがJOINED_FILTERSにマッチする/ **の最後の行を持つSpring Security filterChainを持っているからです。また、Spring Security OAuth2 Providerをインストールするときに追加した行には、/ **のJOINED_FILTERSから他のフィルタを除いたものがあります。その行は実際には正しい行ですが、元の/ **行を削除したことはないので、優先順位はこの行の前に来るということです。だから私がする必要があったのは、JOINED_FILTERSに一致する/ **の最初の行を削除することです。終わり

、フィルターチェーンのより私たちが持っている行は、次のとおりです。

[pattern: '/rest/**', filters: 'JOINED_FILTERS,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-oauth2BasicAuthenticationFilter,-exceptionTranslationFilter'], 
// We want all the other resources to be Web-based 
[pattern: '/web/**', filters: 'JOINED_FILTERS,-statelessSecurityContextPersistenceFilter,-oauth2ProviderFilter,-clientCredentialsTokenEndpointFilter,-oauth2BasicAuthenticationFilter,-oauth2ExceptionTranslationFilter'], 
// This is just a catch-all that defaults to the same logic as before, it also would match things like /oauth/** or /auth/** 
[pattern: '/**',  filters: 'JOINED_FILTERS'] 

そして、我々はまた、私たち自身のAuthController指さオーバーライドのためのいくつかの他の構成があります。

grails.plugin.springsecurity.auth.loginFormUrl = '/auth/login' // This is our own Login Form 
grails.plugin.springsecurity.failureHandler.defaultFailureUrl = '/auth/login' // Exception message shown in controller 
grails.plugin.springsecurity.adh.errorPage = '/auth/denied' // Copied from LoginController 
関連する問題