引言
前端Vue采用Json登陆,通常是跨域的,而且由于是Resulful无状态的请求,认证后的状态都是靠后台发出的token保持。默认的Spring security认证完成后会进行302重定向,这显然不符合我们的要求。登陆成功后我们想返回用户的相关信息,也是Json,这就需要自定义配置。再加上token的处理。。
好在Spring security全部都可以自定义,只是网上都是Sringboot的配置,这次项目使用的繁琐的SpringMVC的xml配置,摸索了好久终于搞定。
1. 明确默认的Spring sercurity filter chain
自定义Spring sercurity,基本上就是自定义各种filter chain。以下是filter chain的顺序跟别名。具体可以查看官网。
这里明确以下我们需要替换的filter。
AliasFilter ClassNamespace Element or Attribute
CHANNEL_FILTER
ChannelProcessingFilter
http/intercept-url@requires-channel
SECURITY_CONTEXT_FILTER
SecurityContextPersistenceFilter
http
CONCURRENT_SESSION_FILTER
ConcurrentSessionFilter
session-management/concurrency-control
HEADERS_FILTER
HeaderWriterFilter
http/headers
CSRF_FILTER
CsrfFilter
http/csrf
LOGOUT_FILTER
LogoutFilter
http/logout
X509_FILTER
X509AuthenticationFilter
http/x509
PRE_AUTH_FILTER
AbstractPreAuthenticatedProcessingFilterSubclasses
N/A
CAS_FILTER
CasAuthenticationFilter
N/A
FORM_LOGIN_FILTER
UsernamePasswordAuthenticationFilter
http/form-login
BASIC_AUTH_FILTER
BasicAuthenticationFilter
http/http-basic
SERVLET_API_SUPPORT_FILTER
SecurityContextHolderAwareRequestFilter
http/@servlet-api-provision
JAAS_API_SUPPORT_FILTER
JaasApiIntegrationFilter
http/@jaas-api-provision
REMEMBER_ME_FILTER
RememberMeAuthenticationFilter
http/remember-me
ANONYMOUS_FILTER
AnonymousAuthenticationFilter
http/anonymous
SESSION_MANAGEMENT_FILTER
SessionManagementFilter
session-management
EXCEPTION_TRANSLATION_FILTER
ExceptionTranslationFilter
http
FILTER_SECURITY_INTERCEPTOR
FilterSecurityInterceptor
http
SWITCH_USER_FILTER
SwitchUserFilter
N/A
2. 自定义FORM_LOGIN_FILTER
首先就是FORM_LOGIN_FILTER,默认使用UsernamePasswordAuthenticationFilter,xml配置为http/form-login。该filter取得用户名跟密码的方法,就是单纯的调用request.getParameter(),这样是无法取得Json形式的用户名跟密码的。
在这里我们创建继承UsernamePasswordAuthenticationFilter的自定义Login filter。
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter{
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException{
ObjectMapper mapper = new ObjectMapper();
UsernamePasswordAuthenticationToken token;
try (InputStream is = request.getInputStream()) {
// 从Json中获取用户名,密码
MAccount mAccount = mapper.readValue(is, MAccount.class);
token = new UsernamePasswordAuthenticationToken(mAccount.getLoginName(), mAccount.getLoginPassword());
} catch (IOException e) {
throw new BadCredentialsException(MessageUtil.getMessage("MSG_LOGIN_FAILURE"));
}
setDetails(request, token);
return this.getAuthenticationManager().authenticate(token);
}
}
复制代码