7

我正在使用 Spring 安全性对用户进行身份验证。我创建了一个自定义身份验证提供程序,现在我想知道如何从提供程序获取错误消息到我的表单中。这是我的自定义身份验证提供程序中的 authenticate() 方法:

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    UserProfile profile = userProfileService.findByEmail(authentication.getPrincipal().toString());

    if(profile == null){
        throw new UsernameNotFoundException(String.format("Invalid credentials", authentication.getPrincipal()));
    }

    String suppliedPasswordHash = DigestUtils.shaHex(authentication.getCredentials().toString());

    if(!profile.getPasswordHash().equals(suppliedPasswordHash)){
        throw new BadCredentialsException("Invalid credentials");
    }

    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(profile, null, profile.getAuthorities());

    return token;
}

这是我的表格:

<form name='f' action="<c:url value='j_spring_security_check' />" method='POST'>
<div id="data-entry-form">

    <div class="form-entry">
        <label><spring:message code="login.form.label.email"/></label>
        <input type='text' name='j_username' value=''>
    </div>
    <div class="form-entry">
        <label><spring:message code="login.form.label.password"/></label>
        <input type='password' name='j_password'/>
    </div>
    <div class="form-entry">
        <input type="submit" value="Verzenden"/>
    </div>
</div>

如何将错误消息输入我的表单?从我按下登录按钮的那一刻起,Spring 就接管了,所以我可以生成错误消息的唯一方法是 authenticate() 方法......

4

3 回答 3

16

最安全的 3 个步骤(我们不依赖 LAST_EXCEPTION):

  1. 在您的自定义身份验证提供程序的配置中指定错误页面(例如“登录错误”)

    httpSecurity
    .authorizeRequests()
    .antMatchers("/css/**", "/js/**", "/img/**").permitAll()
    .anyRequest().fullyAuthenticated()
    .and()
    .formLogin().loginPage("/login").permitAll()
    .failureUrl("/login-error")
    .and()
    .logout().permitAll()
    
  2. 为 url /login-error 创建控制器,返回自定义登录页面的视图(例如“登录”),并使用以下代码:

    @Controller
    public class LoginController {
    
        @GetMapping("/login-error")
        public String login(HttpServletRequest request, Model model) {
            HttpSession session = request.getSession(false);
            String errorMessage = null;
            if (session != null) {
                AuthenticationException ex = (AuthenticationException) session
                        .getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
                if (ex != null) {
                    errorMessage = ex.getMessage();
                }
            }
            model.addAttribute("errorMessage", errorMessage);
            return "login";
        }
    }
    
  3. 最终将错误消息放入您的页面(例如,ThymeLeaf 标签):

    <!--/*@thymesVar id="errorMessage" type="java.lang.String"*/-->
    <div class="alert" th:if="${errorMessage}" th:text="${errorMessage}"></div>
    
于 2019-07-10T13:10:19.740 回答
5

我能够像这样解决它:

<c:if test="${param.auth eq 'failure'}">
  <div class="error">
    <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
  </div>
</c:if>

请注意,您需要通过可以在 spring-security 配置中设置的特殊参数来检测是否存在错误,如下所示:

<security:form-login [...] authentication-failure-url="/login?auth=failure" />

编辑: 实际上,不需要传递该参数。相反,可以简单地检查是否SPRING_SECURITY_LAST_EXCEPTION.message已定义,如下所示:

<c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION.message}">
  <div class="error">
    <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
  </div>
</c:if>
于 2016-07-11T07:19:02.000 回答
4

我认为您应该能够以与使用“标准”身份验证器相同的方式获取消息。如果在身份验证过程中抛出异常(或多个),则最后一个异常存储在会话属性中:SPRING_SECURITY_LAST_EXCEPTION。

因此,要从 JSP 获取最后一条异常消息,您可以使用如下内容:

<%=((Exception) request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION")).getMessage()%>;

当然,如果您有一个控制器,您可能应该从控制器获取消息并仅将字符串传递给 jsp。这只是一个例子;)

于 2012-11-27T11:40:55.470 回答