尝试登录应用程序并收到CredentialsExpiredException后,如何呈现更改密码表单?如何支持其他参数如新密码和确认?
答案 0 :(得分:0)
将WebSecurityConfigurerAdapter实现类配置为:
http.
//...
.antMatchers("/resources/**", "/login", "/index.**").permitAll()
//...
.authenticationDetailsSource(req -> new CustomWebAuthenticationDetails(req))
.failureHandler((req, res, e) -> {
req.getSession().setAttribute("SPRING_SECURITY_LAST_EXCEPTION", e);
res.sendRedirect((e instanceof CredentialsExpiredException) ? CHANGE : FAILURE);
})
//...
其中:
private static final String FAILURE = "/index.html?login_error=true";
private static final String CHANGE = FAILURE + "&change=true";
和
public class CustomWebAuthenticationDetails extends WebAuthenticationDetails {
private Map<String, String> params = new HashMap<>();
public CustomWebAuthenticationDetails(HttpServletRequest req) {
super(req);
put(req, "j_enc_np");
put(req, "j_enc_cnp");
}
private void put(HttpServletRequest req, String key) {
if (req.getParameter(key) != null && !"".equals(key)) {
params.put(key, req.getParameter(key));
}
}
public boolean isChange() {
return !params.isEmpty();
}
public String get(String key) {
return params.get(key);
}
}
准备登录页面以获取其他参数:
<form name="f" id="form-login" action="<c:url value="login"/>" method="post">
<fieldset>
<p><label for="j_enc_u"><spring:message code="app.lbl.username" /></label></p>
<p><input type="text" id="j_enc_u" name="j_enc_u"></p>
<p><label for="j_enc_p"><c:choose><c:when test="${param.change}"><spring:message code="app.lbl.old.password" /></c:when><c:otherwise><spring:message code="app.lbl.password" /></c:otherwise></c:choose></label></p>
<p><input type="password" id="j_enc_p" name="j_enc_p"></p>
<c:if test="${param.change}">
<p><label for="j_enc_np"><spring:message code="app.lbl.new.password" /></label></p>
<p><input type="password" id="j_enc_np" name="j_enc_np"></p>
<p><label for="j_enc_cnp"><spring:message code="app.lbl.new.conf.password" /></label></p>
<p><input type="password" id="j_enc_cnp" name="j_enc_cnp"></p>
</c:if>
<p><input type="submit" value="<spring:message code="app.lbl.validate" />"></p>
</fieldset>
</form>
<c:choose>
<c:when test="${param.login_error}">
<div class="error-message"><c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" /></div>
</c:when>
</c:choose>
准备AuthenticationProvider自定义:
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
final String username = authentication.getPrincipal().toString().trim();
final String password = authentication.getCredentials().toString().trim();
final String encryptedPassword = passwordEncryptor.encryptPassword(password);
final CustomWebAuthenticationDetails cwad = (CustomWebAuthenticationDetails) authentication.getDetails();
try {
final SecUserStatus status =
(cwad.isChange()) ?
authenticationService.resetPassword(username, encryptedPassword, cwad.get("j_enc_np"), cwad.get("j_enc_cnp")) :
authenticationService.authenticate(username, encryptedPassword, cwad.getRemoteAddress());
SecUser secUser = status.getSecUser();
final UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(
secUser,
secUser.getPassword(),
secUser.getAuthorities());
authenticationToken.setDetails(secUser);
authenticationService.lastLogin(secUser.getId(), new Date());
return authenticationToken;
} catch (AuthenticationException e) {
LOGGER.error(e.getMessage(), e);
throw e;
}
}