Problem
After trying to loggin in the application and receiving a CredentialsExpiredException, how to present a change password form? How to support additional parameters such new password and confirmation?
Solution
Configure your WebSecurityConfigurerAdapter implementation class as:
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);
})
//...
Where:
private static final String FAILURE = "/index.html?login_error=true";
private static final String CHANGE = FAILURE + "&change=true";
And:
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);
}
}
Prepare your login page for additional parameters:
<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>Prepare your AuthenticationProvider customization:
@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;
}
}
Aucun commentaire:
Enregistrer un commentaire