java - JAVA - 自定义过滤器验证失败后如何重定向到登录页面?
问题描述
我必须在 Spring-security 的验证过程中添加一些额外的验证。我在配置 xml 中添加了“自定义过滤器”,但是当它失败时将我重定向到错误页面,而不是登录页面。我可以毫无问题地访问我的“authenticationFilter”类,并且当我的凭据良好并进入主页面时我没有问题。
我的 Spring-security 配置是:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<custom-filter
ref="authenticationFilter"
before="FORM_LOGIN_FILTER"
/>
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login"
default-target-url="/home"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password"
/>
<logout logout-success-url="/login?logout" />
</http>
我的过滤器是:
@Component("authenticationFilter")
public class RequestBodyReaderAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private static final Log LOG = LogFactory.getLog(RequestBodyReaderAuthenticationFilter.class);
private static final String ERROR_MESSAGE = "Error en la validación con AD";
private final ObjectMapper objectMapper = new ObjectMapper();
public RequestBodyReaderAuthenticationFilter() {
}
@Autowired
@Qualifier("authenticationManager")
@Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String requestBody;
Boolean valido = false;
try {
requestBody = IOUtils.toString(request.getReader());
ArrayList<String> credenciales = new ArrayList<String>();
for (String val : requestBody.split("&")) {
credenciales.add(val.split("=")[1]);
}
try {
org.tempuri.ADWS service = new org.tempuri.ADWS();
org.tempuri.IADWS port = service.getBasicHttpBindingIADWS();
valido = port.login(credenciales.get(0), credenciales.get(1));
} catch (Exception ex) {
LOG.error(ERROR_MESSAGE, ex);
}
UsernamePasswordAuthenticationToken token;
if (valido) {
token = new UsernamePasswordAuthenticationToken(credenciales.get(0), credenciales.get(1));
setDetails(request, token);
} else {
LOG.error("El usuario " + credenciales.get(0) + " no existe en AD");
token = new UsernamePasswordAuthenticationToken("", "");
setDetails(request, token);
}
return this.getAuthenticationManager().authenticate(token);
} catch (IOException e) {
LOG.error(ERROR_MESSAGE, e);
throw new InternalAuthenticationServiceException(ERROR_MESSAGE, e);
} catch (Exception e) {
LOG.error(ERROR_MESSAGE, e);
throw new InternalAuthenticationServiceException(ERROR_MESSAGE, e);
}
}
}
我需要当“自定义过滤器”的验证失败时,它会重定向到登录页面,而不是抛出 401/403 默认页面。
解决方案
最后我找到了解决我的问题的方法。我为类 RequestBodyReaderAuthenticationFilter 覆盖方法 unsuccessfulAuthentication,并重定向到我的登录错误页面。
我做了很多证明,在所有情况下,这都是成功的。
现在的课是:
@Component("authenticationFilter")
public class RequestBodyReaderAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private static final Log LOG = LogFactory.getLog(RequestBodyReaderAuthenticationFilter.class);
private static final String ERROR_MESSAGE = "Error en la validación con AD";
private final ObjectMapper objectMapper = new ObjectMapper();
public RequestBodyReaderAuthenticationFilter() {
}
@Autowired
@Qualifier("authenticationManager")
@Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
LOG.error("El usuario no existe en AD");
response.sendRedirect(request.getContextPath()+"/login?error"); //To change body of generated methods, choose Tools | Templates.
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String requestBody;
Boolean valido = false;
try {
requestBody = IOUtils.toString(request.getReader());
ArrayList<String> credenciales = new ArrayList<String>();
//Busco el Usu y pass enviados en el request
for (String val : requestBody.split("&")) {
credenciales.add(val.split("=")[1]);
}
try {
//hago el llamado el WS
org.tempuri.ADWS service = new org.tempuri.ADWS();
org.tempuri.IADWS port = service.getBasicHttpBindingIADWS();
valido = port.login(credenciales.get(0), credenciales.get(1));
} catch (Exception ex) {
LOG.error(ERROR_MESSAGE, ex);
}
UsernamePasswordAuthenticationToken token;
if (valido) {
//si existe en AD, realizo la validación en el sistema
token = new UsernamePasswordAuthenticationToken(credenciales.get(0), credenciales.get(1));
setDetails(request, token);
return this.getAuthenticationManager().authenticate(token);
}else{
throw new InternalAuthenticationServiceException(ERROR_MESSAGE);
}
} catch (IOException e) {
LOG.error(ERROR_MESSAGE, e);
throw new InternalAuthenticationServiceException(ERROR_MESSAGE, e);
}
}
}
推荐阅读
- arrays - React Native FlatList 仅渲染 1 个对象
- c++ - 什么模板
模板 做? - servicestack - ServiceStack 和 .NET Core AppSettings 复杂对象
- spring-cloud-dataflow - 如何在 Spring Cloud 数据流中运行多个作业
- sql - postgres中的存储过程更新查询
- node.js - 如何检查 MongoDB 备份数据库?
- html - 如何在 div 上调整图层的高度和宽度
- android - 如何使用 Android CameraX 获取拍摄照片的 ISO 和曝光时间?
- c - 如何轻松地将数组从 INI 文件解析为 C 中的数组?
- python - 在 python 中使用 re.sub() 如何替换某些短语,但前提是它前面有多个字母