在使用过程中,如果有多个账号,需要进行账号切换。我们一般需要用户先注销当前的登录用户,然后在登录另一个账号。
这时候我们就需要使用到退出登录的操作,在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系列文章请 点击这里 查看。
这是代码 码云地址 。
注意注意!!!项目是使用分支的方式来提交每次测试的代码的,请根据章节来我切换分支。