Spring Security-区分错误的用户名/密码组合和未授权用户

时间:2019-06-12 16:09:19

标签: java spring spring-security

在Spring Boot + Spring Security应用程序中,我编写了自己的AuthenticationProvider。它对另一个服务器进行身份验证,该服务器保存有关用户名及其密码的信息。

到目前为止,一切工作正常-通过在安全配置中的failureUrl(String)上使用formLogin(),我可以告诉人们他们使用了无效的用户名/密码组合。 Spring还将自动将未经授权的请求重定向到登录表单。

但是,用户有可能提供有效的用户名/密码组合,但是无论如何根本不允许使用该应用程序。当然,这样的用户不应收到“错误的用户名/密码”相同的反馈,因为这会使他感到困惑。我的AuthenticationProvider或安全配置中是否可以通过某种方式实现这两者之间的区分大小写?到目前为止,我还看不到任何方法,在AuthenticationProvider中返回null会使Spring假定它是“失败”,因此仅重定向到failureUrl(String)中指定的路径。

4 个答案:

答案 0 :(得分:1)

我建议您区分身份验证和授权。具有有效凭据的用户应始终经过身份验证。可能仍会由于缺少授权而拒绝访问。

那么,为所有真正允许使用您的应用程序的用户授予“ USER”角色,以及将您的应用程序配置为针对特定请求要求该角色,例如:

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()                   
        .antMatchers("/api/**").hasRole("USER")                                                            
        .anyRequest().authenticated()                                                               
        .and()
        // ...
        .httpBasic();   
}

答案 1 :(得分:1)

Spring Security使用两个不同的界面来支持这种情况。

AuthenticationFailureHandler

Spring Security使用此API来确定如何处理身份验证失败(例如,信誉不佳)。想要重定向回登录页面是很常见的,因此默认情况下会发生这种情况。但是,您可以使用

对其进行自定义
http
    .formLogin()
        .failureUrl(myUrl)

http
    .formLogin()
        .failureHandler(myFailureHandler)

满足更复杂的需求。

AccessDeniedHandler

虽然说用户已登录,但是他们正在请求一个他们无权访问的受保护资源。

默认情况下,Spring Security返回403,但是也可以将其配置为拒绝访问页面:

http
    .exceptionHandling()
        .accessDeniedPage(myAccessDeniedPage)

http
    .exceptionHandling()
        .accessDeniedHandler(myAccessDeniedHandler)

满足更复杂的需求。

您的AuthenticationProvider应该只专注于对用户进行身份验证-您可以抛出AuthenticationException来指示失败。 UsernamePasswordAuthenticationFilter将负责获取失败的URL,而ExceptionTranslationFilter将获取拒绝访问的页面。

答案 2 :(得分:0)

您可以为未经授权的用户创建自定义类:

public class UnauthorizedException extends AuthenticationException {

    public UnauthorizedException(String msg) {
        super(msg);
    }

}

重要的是,如果您在AuthenticationException实现中使用它,请扩展Spring Security的AuthenticationProvider。只需像这样使用它即可:

throw new UnauthorizedException("Unauthorized to use this application.");

您可能想对消息进行本地化。

此类异常将被放入会话中名为SPRING_SECURITY_LAST_EXCEPTION的属性中。例如,如果您使用Thymeleaf,则可以打印如下消息:

<p data-th-if="${param.error != null and session.SPRING_SECURITY_LAST_EXCEPTION != null}"
   data-th-text="${session.SPRING_SECURITY_LAST_EXCEPTION.message}">
</p>

答案 3 :(得分:-2)

希望这对您有帮助

    @RequestMapping(value = "/login")
public String getLoginPage(@RequestParam(name = "error", required = false) String error, Model model,
        @RequestParam(name = "logout", required = false) String logout) {
    if (error != null) {
        model.addAttribute("message", "Invalid Username or Password");
    }
    if (logout != null) {
        model.addAttribute("logout", "You have Successfully Logged Out");
    }

    return "login";
}

@RequestMapping(value = "/logout-user")
public String logout(HttpServletRequest request, HttpServletResponse response) {
    // fetch the authentication object
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null) {
        // logout and clear out the session and remove the authentication from the
        // security context
        new SecurityContextLogoutHandler().logout(request, response, auth);
    }
    return "redirect:/login?logout";
}

春季安全配置

<http>

    <intercept-url pattern="/**" access="permitAll" />
    <!-- navigate to login url -->
    <form-login login-page="/login" username-parameter="username"
        password-parameter="password" />
    <!-- access forbidden for unauthorized user -->
    <access-denied-handler error-page="/access-denied" />
    <csrf />
</http>