[英]Spring Boot Security: Exception handling with custom authentication filters
我正在使用Spring Boot + Spring Security(java配置)。 我的問題是舊問題,但我發現的所有信息都已過時且大部分都包含xml-config(很難甚至無法適應一段時間)
我正在嘗試使用令牌(不存儲在服務器端)進行無狀態身份驗證。 長話短說 - 它是JSON Web Tokens認證格式的簡單模擬。 我在默認過濾器之前使用兩個自定義過濾器:
TokenizedUsernamePasswordAuthenticationFilter,在入口點成功驗證后創建令牌(“/ myApp / login”)
TokenAuthenticationFilter嘗試使用令牌(如果提供)對所有受限制的URL進行身份驗證。
如果我想要一些,我不明白如何正確處理自定義異常(使用自定義消息或重定向)...過濾器中的異常與控制器中的異常無關,因此它們不會由相同的處理程序處理...
如果我理解得對,我就不能用
.formLogin()
.defaultSuccessUrl("...")
.failureUrl("...")
.successHandler(myAuthenticationSuccessHandler)
.failureHandler(myAthenticationFailureHandler)
自定義異常,因為我使用自定義過濾器......那么這樣做的方法是什么?
我的配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and() .anonymous()
.and() .authorizeRequests()
.antMatchers("/").permitAll()
...
.antMatchers(HttpMethod.POST, "/login").permitAll()
.and()
.addFilterBefore(new TokenizedUsernamePasswordAuthenticationFilter("/login",...), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new TokenAuthenticationFilter(...), UsernamePasswordAuthenticationFilter.class)
}
我們也可以在自定義過濾器中設置AuthenticationSuccessHandler和AuthenticationFailureHandler。
那么在你的情況下,
// Constructor of TokenizedUsernamePasswordAuthenticationFilter class
public TokenizedUsernamePasswordAuthenticationFilter(String path, AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
setAuthenticationSuccessHandler(successHandler);
setAuthenticationFailureHandler(failureHandler);
}
現在使用這些處理程序只需調用onAuthenticationSuccess()
或onAuthenticationFailure()
方法。
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Authentication authentication) throws IOException, ServletException {
getSuccessHandler().onAuthenticationSuccess(request, response, authentication);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException failed)
throws IOException, ServletException {
getFailureHandler().onAuthenticationFailure(request, response, failed);
}
您可以創建自定義身份驗證處理程序類來處理成功或失敗案例。 例如,
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication)
throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authentication);
// Do your stuff, eg. Set token in response header, etc.
}
}
現在處理異常,
public class LoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e)
throws IOException, ServletException {
String errorMessage = ExceptionUtils.getMessage(e);
sendError(httpServletResponse, HttpServletResponse.SC_UNAUTHORIZED, errorMessage, e);
}
private void sendError(HttpServletResponse response, int code, String message, Exception e) throws IOException {
SecurityContextHolder.clearContext();
Response<String> exceptionResponse =
new Response<>(Response.STATUES_FAILURE, message, ExceptionUtils.getStackTrace(e));
exceptionResponse.send(response, code);
}
}
我的自定義響應類,用於生成所需的JSON響應,
public class Response<T> {
public static final String STATUES_SUCCESS = "success";
public static final String STATUES_FAILURE = "failure";
private String status;
private String message;
private T data;
private static final Logger logger = Logger.getLogger(Response.class);
public Response(String status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
public String getStatus() {
return status;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
public String toJson() throws JsonProcessingException {
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
try {
return ow.writeValueAsString(this);
} catch (JsonProcessingException e) {
logger.error(e.getLocalizedMessage());
throw e;
}
}
public void send(HttpServletResponse response, int code) throws IOException {
response.setStatus(code);
response.setContentType("application/json");
String errorMessage;
errorMessage = toJson();
response.getWriter().println(errorMessage);
response.getWriter().flush();
}
}
我希望這有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.