简体   繁体   English

在Spring中为单页应用程序实现注销

[英]Implement logout in Spring for Single Page Application

I'm using Java Web Token (JWT) for authentication in my web app. 我在Web应用程序中使用Java Web令牌(JWT)进行身份验证。 I want to create a /logout Rest endpoint that deletes the JSession cookie on the client side, invalidates the session AND does whatever else is necessary. 我想创建一个/logout Rest端点,该端点在客户端上删除JSession cookie,使会话无效,并执行其他必要的操作。

The front end is a SPA written in React. 前端是用React编写的SPA。

I have the following configure method in the WebSecurityConfig class that extends WebSecurityConfigurerAdapter : 我在扩展WebSecurityConfigurerAdapterWebSecurityConfig类中具有以下configure方法:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .authorizeRequests()
            .antMatchers("/login").permitAll()
        .and()
        .authorizeRequests()
            .antMatchers("/signup").permitAll()
        .and()
        .authorizeRequests()
            .anyRequest().authenticated()
        .and()
        .addFilterBefore(
            new JWTAuthenticationFilter(userDetailsServiceBean()),
            UsernamePasswordAuthenticationFilter.class);
}

I had the following code, but it returns 404 Not found error with the path set to /login . 我有以下代码,但其路径设置为/login ,返回404 Not found错误。 I want to get a HTTP response of 200 and some cleanups instead. 我想获得200HTTP response和一些清除。 what should I do ? 我该怎么办 ?

.logout().logoutUrl("/logout").logoutSuccessHandler(logoutHandler).logoutSuccessUrl("/login").invalidateHttpSession(true)

After some research I found out that if I want to use stateless Rest API design, I shouldn't use any cookie, including JSESSIONID. 经过一番研究,我发现如果我想使用无状态Rest API设计,则不应使用任何cookie,包括JSESSIONID。

Therefore I changed my code to: 因此,我将代码更改为:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .csrf().disable()
        .authorizeRequests()
            .anyRequest().authenticated()
        .and()
        .addFilterBefore(
            new JWTAuthenticationFilter(userDetailsServiceBean()),
            UsernamePasswordAuthenticationFilter.class);
}

Could you first try for login request like this. 您可以先尝试这样的登录请求吗? First add JWTLoginFilter in your WebSecurityConfig . 首先在你的WebSecurityConfig添加JWTLoginFilter。

Pasting code from my sample project: 从我的示例项目粘贴代码:

http.csrf().disable() // disable csrf for our requests.
    .authorizeRequests()
    .antMatchers("/").permitAll()
    .antMatchers(HttpMethod.POST,"/login").permitAll()
    .anyRequest().authenticated()
    .and()
    // We filter the api/login requests
    .addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
    // And filter other requests to check the presence of JWT in header
    .addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
    .addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class);

You wouldn't require CORSFilter if your front end and back end are on same server. 如果您的前端和后端在同一服务器上,则不需要CORSFilter。

Also find below JWTLoginFilter class 也可以在下面的JWTLoginFilter类中找到

   public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter 
    {
    private TokenAuthenticationService tokenAuthenticationService;
    public JWTLoginFilter(String url, AuthenticationManager authenticationManager) {
     super(new AntPathRequestMatcher(url));
     setAuthenticationManager(authenticationManager);
     tokenAuthenticationService = new TokenAuthenticationService();
}

@Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
throws AuthenticationException, IOException, ServletException {
    AccountCredentials credentials = new ObjectMapper().readValue(httpServletRequest.getInputStream(), AccountCredentials.class);
    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword());
    return getAuthenticationManager().authenticate(token);
}

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication)
throws IOException, ServletException {
    String name = authentication.getName();
    tokenAuthenticationService.addAuthentication(response, name);
  }
}

AccountCredential class is simple POJO class containing two fields username and password, which I was using to receive the request. AccountCredential类是简单的POJO类,其中包含两个字段username和password,这是我用来接收请求的字段。

Also please note that UsernamePasswordAuthenticationFilter that we are using require two fields in login request 'username' and 'password'. 还请注意,我们使用的UsernamePasswordAuthenticationFilter在登录请求“用户名”和“密码”中需要两个字段。 Like {"username":"user1","password":"secret1"} {"username":"user1","password":"secret1"}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM