web-dev-qa-db-ja.com

Spring Securityログアウトが機能しない-セキュリティコンテキストをクリアせず、認証済みユーザーがまだ存在する

このトピックに関する記事はたくさんありますが、問題があり、解決策が見つかりません。

私は古典的な春のセキュリティを持っていますJava config:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AuctionAuthenticationProvider auctionAuthenticationProvider;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(auctionAuthenticationProvider);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic();

    ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequest = http.authorizeRequests();

    configureAdminPanelAccess(authorizeRequest);
    configureFrontApplicationAccess(authorizeRequest);
    configureCommonAccess(authorizeRequest);

    http.csrf()
        .csrfTokenRepository(csrfTokenRepository()).and()
        .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);

    http.logout()
        .clearAuthentication(true)
        .invalidateHttpSession(true);
}
...
}

また、AJAXによってWebアプリケーションからログイン/ログアウトする2つのコントローラーメソッドがあります。

ログアウトしたいときは、最初にこのメソッドを呼び出します。これにより、ユーザーセッションをクリアし、セキュリティコンテキストからすべてをクリアします。

@Override
@RequestMapping(value = "/logout", method = GET, produces = APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<Boolean> logout(final HttpServletRequest request, final HttpServletResponse response) {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null){
        new SecurityContextLogoutHandler().logout(request, response, auth);
    }

    return new ResponseEntity<>(Boolean.TRUE, HttpStatus.OK);
}

その後、クライアントWebアプリケーションをリロードし、リロードするたびに、次のコントローラーメソッドを呼び出してユーザーが認証されているかどうかを確認します。

@Override
@RequestMapping(value = "/user", method = GET, produces = APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<UserDetails> user() {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    if (principal instanceof UserDetails) {
        return new ResponseEntity<>((UserDetails) principal, HttpStatus.OK);
    }

    return null;
}

そして、ここで私は最後に認証されたユーザーを受け取ります。以前のログアウト方法では、Springログアウトが機能しないようです。

次のコードでログアウトしようとしたが、成功しなかったことに留意してください。

   @Override
   @RequestMapping(value = "/logout", method = GET, produces = APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity<Boolean> logout(final HttpServletRequest request) {
     try {
         request.logout();

         return new ResponseEntity<>(Boolean.TRUE, HttpStatus.OK);
     } catch (ServletException ex) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("There is a problem with the logout of the user", ex);
         }
    }

私の設定とログアウトプロセスで私が見逃していることはありますか?

10
Streetsouls

あなたの質問から、私はあなたがあなた自身のログアウトを作成しようとしていることを確認し、デフォルトの春のログアウトを使用しようとしています。両方を混在させないで1つの方法を選択することをお勧めします。 :

最初:デフォルトのスプリングセキュリティログアウト

.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/logout.done").deleteCookies("JSESSIONID")
.invalidateHttpSession(true) 

上記の例から、ユーザーをログアウトするときはいつでも/logout urlを呼び出すだけで済みます。 @Controllerを作成してそのログアウトを処理する必要はありませんが、代わりにspringはユーザーのログアウトに役立ちます。また、ここで無効にする他の項目を追加することもできます。

2番目:プログラムでログアウト

@RequestMapping(value = {"/logout"}, method = RequestMethod.POST)
public String logoutDo(HttpServletRequest request,HttpServletResponse response){
HttpSession session= request.getSession(false);
    SecurityContextHolder.clearContext();
         session= request.getSession(false);
        if(session != null) {
            session.invalidate();
        }
        for(Cookie cookie : request.getCookies()) {
            cookie.setMaxAge(0);
        }

    return "logout";
}

このログアウトを使用している場合、スプリングセキュリティ設定に最初の方法を含める必要はありません。このメソッドを使用することにより、ログアウトの前後に実行するアクションを追加できます。このログアウトを使用するには、/logout urlを呼び出すだけで、ユーザーは手動でログアウトします。コンテキストとクッキー。

2番目の方法に加えて、RequestMethod.POSTを使用している場合は、csrfキーを投稿として含める必要があります。別の方法は、非表示の入力csrfキーを持つフォームを作成することです。これはjqueryで自動生成されたログアウトリンクの例です。

$("#Logout").click(function(){
    $form=$("<form>").attr({"action":"${pageContext.request.contextPath}"+"/logout","method":"post"})
    .append($("<input>").attr({"type":"hidden","name":"${_csrf.parameterName}","value":"${_csrf.token}"}))
    $("#Logout").append($form);
    $form.submit();
});

ハイパーリンク<a id="Logout">Logout</a>を作成するだけで使用できます。

RequestMethod.GETを使用している場合は、次のようにリンクにパラメーターとしてcsrfキーを含めるだけです。

<a href="${pageContext.request.contextPath}/logout?${_csrf.parameterName}=${_csrf.token}">Logout</a>

それがすべて、その助けを願っています。

31
FreezY

これは助けになります、clearAuthentication(true)で十分だと思います:

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter {

....

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http
        .httpBasic()
        .and()
        .logout().clearAuthentication(true)
        .logoutSuccessUrl("/")
        .deleteCookies("JSESSIONID")
        .invalidateHttpSession(true)
        .and()
1
Laci

Application.propertiesファイルに次のパラメーターを追加して、同様に問題を解決しました

spring.cache.type=NONE
0
Kaique Dias

ちょっと前に、以下に示すように Clear Site Data HTTPヘッダーがあります

Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"

また、Clear-Site-DataヘッダーのサポートをSpring-Security 5.2プロジェクトに追加するのを手伝いました。実装の詳細については、 [〜#〜] pr [〜#〜] を参照してください。

これがどのように機能するかのサンプルです

@EnableWebSecurity
static class HttpLogoutConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .logout()
                    .addLogoutHandler(new HeaderWriterLogoutHandler(
                           new ClearSiteDataHeaderWriter(SOURCE)));
    }
}

SOURCEは、次の1つ以上のvarargです

  • "*"すべてをクリア
  • 1つ以上の"cache", "cookies", "storage", "executionContexts"

詳細については、 LogoutConfigurerClearSiteDataTests.Java のサンプルテストを参照してください。

0
Raf