问题描述
我正在尝试创建自定义 Spring Security 身份验证过滤器以实现自定义身份验证方案。我花了几个小时阅读 Spring Security,但我找到的所有指南都解释了如何配置基本设置;我正在尝试编写自定义设置,但无法找到有关如何执行此操作的文档。
举个例子,假设我的自定义身份验证方案如下: 如果客户端在 http 请求中提供了“foo_username”标头和“foo_password”标头(为了示例,两者都未加密),那么我的自定义过滤器需要构造一个 UsernamePasswordAuthenticationToken。当然,如果密码错误,那就是身份验证错误。如果缺少任一标头,则是身份验证错误。如果两个标头都丢失,我想在不更改任何内容的情况下将过滤器链委托给下游。
这在理论上似乎很简单,但我不知道如何在 Spring 中实现它。我打算自己检查数据库的密码吗?或者这是 UserDetailsPasswordService 的责任?我是否打算自己修改 SecurityContextHolder.getContext().authentication 字段?我将哪些职责委派给 AuthenticationManager?当身份验证以各种方式失败时,我会抛出哪些异常?我是否实现了 Filter、OncePerRequestFilter 或 AbstractAuthenticationFilter?有没有关于如何做到这一切的文档???
诚然,这是How to create your own security filter using Spring security?的重复,但我不是他,他也没有答案。
感谢您的帮助!
解决方法
正如其他人所指出的,最好使用 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,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);
}
}