繁体   English   中英

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

[英]How to create a custom authentication filter in Spring Security?

我正在尝试创建自定义 Spring 安全身份验证过滤器以实施自定义身份验证方案。 我花了几个小时阅读 Spring Security,但我找到的所有指南都解释了如何配置基本设置; 我正在尝试编写自定义设置,但找不到有关如何执行此操作的文档。

例如,假设我的自定义身份验证方案如下:如果客户端在 http 请求中提供“foo_username”header 和“foo_password”header(为了示例均未加密),那么我的自定义过滤器需要构造一个UsernamePasswordAuthenticationToken。 当然,如果密码错误,那就是认证错误。 如果缺少 header 中的任何一个,那就是身份验证错误。 如果两个标头都丢失,我想在不更改任何内容的情况下委托过滤器链。

这在理论上似乎很简单,但我不知道如何在 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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM