我已成功使用Spring-Boot和基于表单的身份验证设置Spring-Security MVC应用程序。我使用thymeleaf实现了一个自定义登录表单,基本上看起来像:
<form th:action="@{/login}" method="POST">
<label for="username">Username</label>
<input type="text" id="username" name="username"/>
<label for="password">Password</label>
<input type="password" id="password" name="password"/>
<button type="submit">Log in</button>
</form>
表单在扩展addViewControllers
的类的WebMvcConfigurerAdapter
方法中注册为简单的“视图控制器”,如:
public class LoginController extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login/login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
到目前为止这是有效的。有一件事困扰我:在登录尝试失败后,应用程序返回到登录表单(这很好),但两个字段都被清除。我想在输入字段中保留用户名(如果密码拼写错误的话)。
我试过
<input type="text" id="username" name="username" th:value="username"/>
但这没有帮助。
有没有办法从百万富翁模板中的失败尝试中获取用户名?我需要为此编写一个显式控制器吗?
答案 0 :(得分:1)
此问题的关键在于SimpleUrlAuthenticationFailureHandler
(默认AuthenticationFailureHandler
)执行重定向 - 因此请求参数(包括用户名)将无法用于登录表单。
奇怪的是,对于这样一个显而易见的事情,似乎并不是一个优雅的解决方案。
如果您只需要保留用户名,那么快速(尽管不是很满意)的选项是在模板中使用SPRING_SECURITY_LAST_EXCEPTION.authentication.principal
(但请注意,首次访问该页面时它将为空)。 / p>
然而,您会发现“记得我”的相同问题。复选框,如果你使用它。
我最终扩展了SimpleUrlAuthenticationFailureHandler
并在重定向之前将我想要保留的请求参数(username
和remember-me
)添加到网址。
我很想知道是否有更好的方法来做到这一点。
答案 1 :(得分:0)
正如马丁·威尔逊已经指出的那样,这个问题没有优雅的解决方案。但是,我在Spring MVC应用程序中解决了这个问题而没有使用额外的URL参数。希望这也有助于你。
我将ExceptionMappingAuthenticationFailureHandler
扩展为在会话参数(USERNAME_PARAMETER
)中存储登录表单的用户名参数(LAST_USERNAME_KEY
):
public class CustomAuthenticationFailureHandler extends ExceptionMappingAuthenticationFailureHandler {
// Username field name in the login form
private final static String USERNAME_PARAMETER = "email";
// Parameter for retained username
private static final String LAST_USERNAME_KEY = "LAST_USERNAME";
public CustomAuthenticationFailureHandler(String defaultFailureUrl) {
super.setDefaultFailureUrl(defaultFailureUrl);
}
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
super.onAuthenticationFailure(request, response, exception);
String lastUserName = request.getParameter(USERNAME_PARAMETER);
// Store the given username in the session
try {
HttpSession session = request.getSession(false);
if (session != null || isAllowSessionCreation()) {
request.getSession().setAttribute(LAST_USERNAME_KEY, lastUserName);
}
} catch (IllegalStateException illegalStateException) {
LOGGER.debug(Arrays.toString(illegalStateException.getStackTrace()));
}
}
}
这必须注册为bean:
@Bean
public LogoutSuccessHandler CustomLogoutSuccessHandler() {
// To redirect to previous url.
return new CustomLogoutSuccessHandler("/access");
}
它在我的登录表单中如下工作。现在,会话参数LAST_USERNAME
包含最后一个用户名:
<input class="form-control" name="email" id="email" value="${LAST_USERNAME}" required>