4

カスタム認証失敗ハンドラーをSpring 3.1.3で動作させるために、私はすでに一日中試しています。

適切に設定されていると思います

<http use-expressions="true" disable-url-rewriting="true">
    <intercept-url pattern="/rest/login" access="permitAll" />
    <intercept-url pattern="/rest/**" access="isAuthenticated()" />
    <intercept-url pattern="/index.html" access="permitAll" />
    <intercept-url pattern="/js/**" access="permitAll" />
    <intercept-url pattern="/**" access="denyAll" />
    <form-login username-parameter="user" password-parameter="pass" login-page="/rest/login"
        authentication-failure-handler-ref="authenticationFailureHandler"  />
</http>
<beans:bean id="authenticationFailureHandler" class="LoginFailureHandler" />

私の実装はこれです

public class LoginFailureHandler implements AuthenticationFailureHandler {
    private static final Logger log = LoggerFactory.getLogger(LoginFailureHandler.class);

    public LoginFailureHandler() {
        log.debug("I am");
    }

    @Autowired
    private ObjectMapper customObjectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {
        log.debug("invalid login");
        User user = new User();
        user.setUsername("invalid");
        try (OutputStream out = response.getOutputStream()) {
            customObjectMapper.writeValue(out, user);
        }
    }

}

私が見るコンソールで

2013-04-11 14:52:29,478 DEBUG LoginFailureHandler - I am

それでロードされます。

ユーザー名またはパスワードが間違っていると、BadCredentialsException がスローされたときに、無効なログインが表示されません。

メソッド onAuthenticationFailure は呼び出されません。

代わりに、サービスはブラウザを /rest/login に何度もリダイレクトします...

編集

2013-04-11 15:47:26,411 DEBUG de.pentos.spring.LoginController - Incomming login chuck.norris, norris
2013-04-11 15:47:26,412 DEBUG o.s.s.a.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2013-04-11 15:47:26,415 DEBUG o.s.s.a.d.DaoAuthenticationProvider - Authentication failed: password does not match stored value
2013-04-11 15:47:26,416 DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception from handler [public de.pentos.spring.User de.pentos.spring.LoginController.login(de.pentos.spring.User)]: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2013-04-11 15:47:26,419 DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from handler [public de.pentos.spring.User de.pentos.spring.LoginController.login(de.pentos.spring.User)]: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2013-04-11 15:47:26,419 DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from handler [public de.pentos.spring.User de.pentos.spring.LoginController.login(de.pentos.spring.User)]: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2013-04-11 15:47:26,426 DEBUG o.s.web.servlet.DispatcherServlet - Could not complete request
org.springframework.security.authentication.BadCredentialsException: Bad credentials

これは DEBUG モードで発生します

私の間違いはどこですか?

4

4 に答える 4

3

添付のログから判断すると、ログイン プロセスの実装に誤りがあると思われます。絶対に確信は持てませんがProviderManager.authenticate()、あなたがLoginController. BadCredentialsExceptionこのメソッドは、 Spring MVC の例外処理メカニズムを起動させる をスローしますが、これにはもちろんAuthenticationFailureHandler、Spring Security 用に構成された に関する知識はありません。

通常、ログイン コントローラからは、単純なログイン フォームを提供するだけaction="j_spring_security_check" method="post"です。ユーザーがそのフォームを送信すると、構成されたセキュリティ フィルター (つまりUsernamePasswordAuthenticationFilter) がその要求をインターセプトし、認証を処理します。コントローラー メソッドでそのロジックを自分で実装する必要はありません。


コメントへの返信:

使用しますProviderManager(これは、自動配線されたインターフェースの実装ですAuthenticationManager )。あなたが犯す間違いは、すでに実装され、認証フィルターで徹底的にテストされているロジックを書き直そうとすることです。これはそれ自体悪いことですが、それでも間違った方法で行われます。複雑なロジックからほんの数行を選択するだけで、たとえばセッション戦略の呼び出し (セッション固定攻撃を防ぎ、同時セッションを処理するため) などを忘れてしまいます。AuthenticationFailureHandler 元の実装も同様に呼び出しますが、これもメソッドで忘れていました。これが、元の質問の問題のまさにその理由です。

そのため、フレームワークとうまく統合してその堅牢性と全容量を活用する代わりに、テストされていない脆弱なソリューションになってしまいます。私が言ったように、回答に投稿した構成は、フレームワークが提供するフィルターを認証に使用するため、明確な改善です。その構成を保持して削除します。LoginController.login()とにかく、に送信されたリクエストによって呼び出されることはありません/rest/login

より基本的な質問は、RESTful サービスを実装する場合、セッションとフォームベースのログイン メカニズムを使用することが本当に良い解決策であるかどうかです。(フォームベースのログインでは、クライアントが資格情報を何らかの形式で一度送信し、その後のリクエストでステートフル セッションによって認証されることを意味します。) REST サービスでは、すべてをステートレスに保ち、新しいリクエストごとに再認証することがより一般的です。 http ヘッダーによって運ばれる情報によって。

于 2013-04-11T14:32:04.783 に答える
1

security-app-context.xml の順序に問題があります。

最初にすべての Bean を定義してから、残りのすべてを定義すると、機能します。私はたくさん試したので、疑問に思わないでください。質問とは少し異なって見えます

<beans:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <beans:property name="loginFormUrl" value="/rest/login" />
</beans:bean>

<beans:bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    <beans:property name="authenticationManager" ref="authenticationManager" />
    <beans:property name="filterProcessesUrl" value="/rest/login" />
    <beans:property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
    <beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
</beans:bean>

<beans:bean id="authenticationSuccessHandler" class="de.pentos.spring.LoginSuccessHandler" />
<beans:bean id="authenticationFailureHandler" class="de.pentos.spring.LoginFailureHandler" />

<http use-expressions="true" disable-url-rewriting="true" entry-point-ref="authenticationProcessingFilterEntryPoint"
    create-session="ifRequired">
    <intercept-url pattern="/rest/login" access="permitAll" />
    <intercept-url pattern="/rest/**" access="isAuthenticated()" />
    <intercept-url pattern="/index.html" access="permitAll" />
    <intercept-url pattern="/js/**" access="permitAll" />
    <intercept-url pattern="/**" access="denyAll" />
    <custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" />
</http>

<authentication-manager alias="authenticationManager">
    <authentication-provider>
        <user-service>
            <user name="chuck.norris" password="cnorris" authorities="ROLE_ADMIN" />
            <user name="user" password="user" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
</authentication-manager>
于 2013-04-11T14:26:48.313 に答える
0

私には悪く見えません。IDE のデバッグ モードを使用しようとしましたか?

ログに次のようなものを見ましたか:

Authentication request failed: ...
Updated SecurityContextHolder to contain null Authentication
Delegating to authentication failure handler ...

AuthenticationFailureHandler は、認証フィルターの 1 つで認証が行われた場合にのみ、自動的に呼び出されます。

于 2013-04-11T13:34:15.320 に答える