Java 如何在spring中仅为一个用户角色启用X.509相互身份验证?

Java 如何在spring中仅为一个用户角色启用X.509相互身份验证?,java,spring,authentication,spring-security,x509,Java,Spring,Authentication,Spring Security,X509,我已经构建了一个SpringBootWebApp,它具有SpringSecurity和一个使用spring应用程序的REST服务的角度前端。我现在有两个用户角色: 使用者 管理员 用户和管理员应该通过用户名和密码进行身份验证,这已经起作用了,但我根本不使用Spring用户角色。相反,我通过angular consumend rest服务和令牌(JWT)构建自己的身份验证 现在我想添加一个超级管理员,它访问与管理员相同的服务,但必须使用客户端证书(X.509)进行身份验证。 如果用户是超级管理

我已经构建了一个SpringBootWebApp,它具有SpringSecurity和一个使用spring应用程序的REST服务的角度前端。我现在有两个用户角色:

  • 使用者
  • 管理员
用户和管理员应该通过用户名和密码进行身份验证,这已经起作用了,但我根本不使用Spring用户角色。相反,我通过angular consumend rest服务和令牌(JWT)构建自己的身份验证 现在我想添加一个超级管理员,它访问与管理员相同的服务,但必须使用客户端证书(X.509)进行身份验证。
如果用户是超级管理员,我如何告诉Spring仅使用X.509进行身份验证
我必须为此使用Spring用户角色吗?

解决此问题的一种方法是使用自定义筛选器。在这种情况下,可以扩展。您可以重写筛选器的doFilter()方法并修改逻辑以对用户类型执行检查,然后从X509AuthenticationFilter调用doFilter()方法,或者通过使用自己的AuthenticationProvider处理JWT

以下代码示例显示了如何创建和集成自定义X509AuthenticationFilter,但不是如何启用基于X509的身份验证的指南

Web安全配置适配器示例:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Autowired
    private CustomX509AuthenticationFilter customX509AuthenticationFilter;

    @Autowired
    private  AuthenticationProvider jwtAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(jwtAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.x509().x509AuthenticationFilter(customX509AuthenticationFilter);
    }
}
自定义X509AuthenticationFilter示例:

@Component
public class CustomX509AuthenticationFilter extends X509AuthenticationFilter {

    private final AuthenticationManager authenticationManager;

    @Autowired
    public CustomX509AuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if(isAdminUser(request)){
            super.doFilter(request, response, chain);
        }
        else {
            Authentication unauthenticatedToken = getUserCredentialsFromRequest(request);
            Authentication authenticatedToken = authenticationManager.authenticate(unauthenticatedToken);
            if(authenticatedToken.isAuthenticated()) {
                SecurityContextHolder.getContext().setAuthentication(authenticatedToken);
                chain.doFilter(request, response);
            }
            else {
                throw new BadCredentialsException("Invalid Credentials");
            }
        }
    }

    private Authentication getUserCredentialsFromRequest(ServletRequest request) {
        // logic to retrieve user credentials from request and create initial Authentication
        return ...
    }

    private boolean isAdminUser(ServletRequest request) {
        // logic to determine whether or not user is admin
        return ...
    }
}

不,如果用户具有角色superadmin:D,您必须将前端设置为仅发送证书验证,但如果您尚未登录,所以还不知道角色,您希望如何发送证书验证?:)使用不同的登录点,在该点上使用不同的凭据并需要证书。我希望超级管理员与用户和管理员登录在同一页面上。为了以后访问rest服务,superadmin应在每个请求上通过证书进行身份验证。如果您在头中传递它,您可以读取特定头并检查它是否为空。如果不是空的-执行admin login,否则执行-userlogin