在Spring Boot + Spring Security应用程序中,我编写了自己的AuthenticationProvider
。它对另一个服务器进行身份验证,该服务器保存有关用户名及其密码的信息。
到目前为止,一切工作正常-通过在安全配置中的failureUrl(String)
上使用formLogin()
,我可以告诉人们他们使用了无效的用户名/密码组合。 Spring还将自动将未经授权的请求重定向到登录表单。
但是,用户有可能提供有效的用户名/密码组合,但是无论如何根本不允许使用该应用程序。当然,这样的用户不应收到“错误的用户名/密码”相同的反馈,因为这会使他感到困惑。我的AuthenticationProvider
或安全配置中是否可以通过某种方式实现这两者之间的区分大小写?到目前为止,我还看不到任何方法,在AuthenticationProvider
中返回null会使Spring假定它是“失败”,因此仅重定向到failureUrl(String)
中指定的路径。
答案 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>