在我們訪問接口時常常會遇到登錄失效的問題,例如:登錄超時、服務器重啟這些都會導致登錄失效。
Spring Security 在用戶登錄時效后,會自動跳轉到了登錄頁面去,在前后端分離的情況下,我們希望能像登錄授權那樣,登錄失效也能返回 JSON 字符串。
一、登錄失效處理程序
登錄失敗處理程序和登錄授權這些一樣,我們只要實現 AuthenticationEntryPoint
這個接口就可以了。
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.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 未登錄或者登錄失效
*
* @author lixingwu
*/
@Component
public class JsonAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(
HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException
) throws IOException, ServletException {
Console.log("未登錄或者登錄失效,{}", authException);
Dict res = Dict.create()
.set("code", 1001)
.set("msg", "未登錄或者登錄失效")
.set("data", authException.getMessage());
ServletUtil.write(response, JSONUtil.toJsonStr(res), ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8));
}
}
二、配置登錄失效處理程序
我們現在把我們寫的 登錄失效
處理程序配置到HttpSecurity上,這樣在登錄失效時就返回我們設置的json字符串了。注意:這個操作會導致默認的登錄頁面不可使用,完整配置看代碼。
import com.miaopasi.securitydemo.config.security.handler.JsonAccessDeniedHandler;
import com.miaopasi.securitydemo.config.security.handler.JsonAuthenticationEntryPoint;
import com.miaopasi.securitydemo.config.security.handler.JsonFailureHandler;
import com.miaopasi.securitydemo.config.security.handler.JsonSuccessHandler;
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 lixingwu
*/
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JsonSuccessHandler successHandler;
private final JsonFailureHandler failureHandler;
private final JsonAccessDeniedHandler accessDeniedHandler;
private final JsonAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
public SecurityConfig(JsonSuccessHandler successHandler, JsonFailureHandler failureHandler, JsonAccessDeniedHandler accessDeniedHandler, JsonAuthenticationEntryPoint authenticationEntryPoint) {
this.successHandler = successHandler;
this.failureHandler = failureHandler;
this.accessDeniedHandler = accessDeniedHandler;
this.authenticationEntryPoint = authenticationEntryPoint;
}
@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)
.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");
}
}
三、測試
我在 application.yml
中設置session的超時時間為30s,
server:
servlet:
session:
timeout: 30s
然后登錄,30s內訪問正常訪問,超過30s后訪問,返回json字符串。
在未登錄時,我們直接請求接口 /admin/get
、/guest/get
返回json字符串。
{
"msg": "未登錄或者登錄失效",
"code": 1001,
"data": "Full authentication is required to access this resource"
}
spring security系列文章請 點擊這里 查看。
這是代碼 碼雲地址 。
注意注意!!!項目是使用分支的方式來提交每次測試的代碼的,請根據章節來我切換分支。