• Spring Security6、登录用户退出登录操作


    在使用过程中,如果有多个账号,需要进行账号切换。我们一般需要用户先注销当前的登录用户,然后在登录另一个账号。

    这时候我们就需要使用到退出登录的操作,在Spring Security中默认调用接口 /logout 进行登出操作,登出成功后会自动跳转到登录页面。

    在前后端分离的情况下,我们希望能像登录授权那样,登出成功后也能返回 JSON 字符串。

    一、退出登录成功处理程序

    登录失败处理程序和登录授权这些一样,我们只要实现 LogoutSuccessHandler 这个接口就可以了。

    import cn.hutool.core.lang.Console;
    import cn.hutool.core.lang.Dict;
    import cn.hutool.core.util.CharsetUtil;
    import cn.hutool.extra.servlet.ServletUtil;
    import cn.hutool.http.ContentType;
    import cn.hutool.json.JSONUtil;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * 退出成功
     *
     * @author lixin
     */
    @Component
    public class JsonLogoutSuccessHandler implements LogoutSuccessHandler {
        @Override
        public void onLogoutSuccess(
                HttpServletRequest request, HttpServletResponse response,
                Authentication authentication
        ) throws IOException, ServletException {
            Console.log("退出成功,{}", authentication);
            Dict res = Dict.create()
                    .set("code", 0)
                    .set("msg", "退出成功")
                    .set("data", authentication);
            ServletUtil.write(response, JSONUtil.toJsonStr(res), ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8));
        }
    }
    
    

    二、配置退出登录成功处理程序

    我们现在把我们写的 退出登录成功 处理程序配置到HttpSecurity上,这样在 退出登录成功 时就返回我们设置的json字符串了,完整配置看代码。

    import com.miaopasi.securitydemo.config.security.handler.*;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    
    /**
     * Security配置类,会覆盖yml配置文件的内容
     *
     * @author lixin
     */
    @EnableWebSecurity
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        private final JsonSuccessHandler successHandler;
        private final JsonFailureHandler failureHandler;
        private final JsonAccessDeniedHandler accessDeniedHandler;
        private final JsonAuthenticationEntryPoint authenticationEntryPoint;
        private final JsonLogoutSuccessHandler logoutSuccessHandler;
    
        @Autowired
        public SecurityConfig(JsonSuccessHandler successHandler, JsonFailureHandler failureHandler, JsonAccessDeniedHandler accessDeniedHandler, JsonAuthenticationEntryPoint authenticationEntryPoint, JsonLogoutSuccessHandler logoutSuccessHandler) {
            this.successHandler = successHandler;
            this.failureHandler = failureHandler;
            this.accessDeniedHandler = accessDeniedHandler;
            this.authenticationEntryPoint = authenticationEntryPoint;
            this.logoutSuccessHandler = logoutSuccessHandler;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/code", "/login", "/logout", "/doLogin").permitAll()
                    .antMatchers("/admin/**", "/guest/**").hasRole("admin")
                    .antMatchers("/guest/**").hasRole("guest")
                    .anyRequest().authenticated()
                    .and().formLogin()
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .loginProcessingUrl("/doLogin")
                    .successHandler(successHandler)
                    .failureHandler(failureHandler)
                
                	// 退出登录,默认为/logout,这里修改接口地址为 /doLogout
                    .and().logout().logoutUrl("/doLogout")
                    // 设置退出登录成功处理程序,退出成功后返回JSON字符串
                    .logoutSuccessHandler(logoutSuccessHandler)
                
                    .and().exceptionHandling()
                    .accessDeniedHandler(accessDeniedHandler)
                    .authenticationEntryPoint(authenticationEntryPoint)
                    .and().cors()
                    .and().csrf().disable();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .passwordEncoder(new BCryptPasswordEncoder())
                    .withUser("admin")
                    .password(new BCryptPasswordEncoder().encode("123456"))
                    .roles("admin", "guest")
                    .and()
                    .withUser("user")
                    .password(new BCryptPasswordEncoder().encode("000000"))
                    .roles("guest");
        }
    }
    
    

    三、测试

    我们先登录用户admin,然后请求接口 /admin/get ,能正常访问。

    然后我们使用get方式调用接口 /doLogout,接口返回JSON字符串:

    {
      "msg": "退出成功",
      "code": 0,
      "data": {
        "authenticated": true,
        "authorities": [
          {},
          {}
        ],
        "principal": {
          "credentialsNonExpired": true,
          "authorities": [
            {},
            {}
          ],
          "enabled": true,
          "accountNonExpired": true,
          "username": "admin",
          "accountNonLocked": true
        },
        "details": {
          "remoteAddress": "127.0.0.1"
        }
      }
    }
    

    退出成功后,我们再请求接口 /admin/get ,发现返回JSON字符串:

    {
      "msg": "未登录或者登录失效",
      "code": 1001,
      "data": "Full authentication is required to access this resource"
    }
    

    然后我们重新登录后继续请求接口 /admin/get ,发现正常请求到数据。

    spring security系列文章请 点击这里 查看。
    这是代码 码云地址
    注意注意!!!项目是使用分支的方式来提交每次测试的代码的,请根据章节来我切换分支。

  • 相关阅读:
    [转]开源游戏AI引擎列表与游戏中的人工智能
    [转]刨根问底!曲面细分技术到底是个啥?
    [转]link time code generation
    [转]PythonQt
    [转]Free Game Development Libraries
    Java虚拟机(二):垃圾回收算法 时间
    Java虚拟机(一):JVM的运行机制 时间
    Java虚拟机(四):常用JVM配置参数 时间
    Java虚拟机(三):垃圾收集器 时间
    mov offset和lea的区别
  • 原文地址:https://www.cnblogs.com/lixingwu/p/13291255.html
Copyright © 2020-2023  润新知