如何在SpringSecurity中创建自定义身份验证过滤器



我正在尝试创建一个自定义的Spring安全身份验证过滤器,以便实现一个自定义身份验证方案。我花了几个小时阅读了Spring Security,但我找到的所有指南都解释了如何配置基本设置;我正在尝试编写一个自定义设置,但我很难找到如何做到这一点的文档

为了举例说明,假设我的自定义身份验证方案如下:如果客户提供一个";foo_username"标题和一个";foo_password"http请求中的头(为了示例起见,两者都未加密(,那么我的自定义过滤器需要构造一个UsernamePasswordAuthenticationToken。当然,如果密码是错误的,那就是身份验证错误。如果其中一个标头丢失,则表示身份验证错误。如果两个标头都丢失了,我希望在不更改任何内容的情况下委托过滤器链。

这在理论上似乎很简单,但我不知道如何在Spring中实现。我打算自己对照数据库检查密码吗?或者这是UserDetailsPasswordService的责任?我是否打算自己修改SecurityContextHolder.getContext((.authentication字段?我将哪些职责委派给AuthenticationManager?当身份验证以各种方式失败时,我会抛出哪些异常?我实现Filter、OncePerRequestFilter还是AbstractAuthenticationFilter?有关于如何做到这一切的文件吗???

诚然,这是《如何使用Spring安全创建自己的安全过滤器?》的翻版?,但我不是他,他没有答案。

谢谢你的帮助!

编辑:这不是最好的方法。它没有遵循最佳实践

正如其他人所指出的,最好使用Basic auth或OAuth2,这两种方法都内置在Spring中。但是,如果你真的想实现一个自定义过滤器,你可以这样做。(如果我做错了,请纠正我。(但不要这么做。这不是一个非常安全的例子;这是一个简单的例子。

class CustomAuthenticationFilter(val authManager: AuthenticationManager) : OncePerRequestFilter() {
override fun doFilterInternal(request: HttpServletRequest,
response: HttpServletResponse,
chain: FilterChain) {
val username = request.getHeader("foo_username")
val password = request.getHeader("foo_password")
if(username==null && password==null){
// not our responsibility. delegate down the chain. maybe a different filter will understand this request.
chain.doFilter(request, response) 
return
}else if (username==null || password==null) {
// user is clearly trying to authenticate against the CustomAuthenticationFilter, but has done something wrong.
response.status = 401
return
}
// construct one of Spring's auth tokens
val authentication =  UsernamePasswordAuthenticationToken(username, password, ArrayList())
// delegate checking the validity of that token to our authManager
val userPassAuth = this.authManager.authenticate(authRequest)
// store completed authentication in security context
SecurityContextHolder.getContext().authentication = userPassAuth
// continue down the chain.
chain.doFilter(request, response)
}
}

创建了身份验证过滤器后,不要忘记将其添加到HttpSecurity配置中,如下所示:

override fun configure(http: HttpSecurity?) {
http!!.addFilterBefore(CustomAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter::class.java)
}

我认为您想要做的是实现AuthenticationProvider。它允许您的代码显式地管理身份验证部分。它还有一个相当简单的方法签名要实现。

public class YourAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
...
return new UsernamePasswordAuthenticationToken(principal, password, principal.getAuthorities())
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}

您可以在扩展WebSecurityConfigurerAdapter 的配置中将其添加到AuthenticationManagerBuilder中进行注册

@Configuration
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) {
AuthenticationProvider provider= new YourAuthenticationProvider();
auth.authenticationProvider(provider);
}
}

最新更新