使用 javassist 注入 Spring 安全配置代码

Injecting Spring security config code using javaassist

我有一个 spring 引导应用程序,在应用程序启动期间,我试图使用 Java 注入 Spring-安全 Java 配置助攻。我正在从 DB 的值动态生成 java 配置。这是代码,

public class WarLock implements SpringApplicationRunListener {
private final SpringApplication application;

public WarLock(SpringApplication application, String[] args) throws IOException {
    this.application = application;
}

@Override
public void started() {
    try {
        System.out.println("Re-write security config called");
        rewriteSecurityConfigClass();
    } catch (NotFoundException | CannotCompileException e) {
        e.printStackTrace();
    }
}

private void rewriteSecurityConfigClass() throws NotFoundException, CannotCompileException {

    SecurityConfig config = new SecurityConfig();

    ClassPool cp = ClassPool.getDefault();
    cp.appendClassPath(new LoaderClassPath(application.getClassLoader()));
    CtClass compiledClass = cp.get(config.getClass().getName());

    CtClass[] argClasses = { cp.get(HttpSecurity.class.getName()) };

    CtMethod method = compiledClass.getDeclaredMethod("configure",argClasses);

    method.setBody("http    .csrf().disable()                   "+
            ".authorizeRequests()                               "+
            "   .antMatchers(\"/css/**\", \"/index\").permitAll()   "+
            "   .antMatchers(\"/user/**\").hasAuthority(\"USER\")   "+
            "   .antMatchers(\"/tryadmin\").hasAuthority(\"ADMIN\") "+
            "   .antMatchers(\"/try\").hasAuthority(\"USER\")       "+
            "   .and()                                          "+
            ".authenticationProvider(authenticationProvider())  "+
            "   .exceptionHandling()                            "+
            "   .authenticationEntryPoint(entryPoint)           "+
            "   .and()                                          "+
            ".formLogin()                                       "+
            "   .usernameParameter(\"username\")                    "+
            "   .passwordParameter(\"password\")                    "+
            "   .successHandler(loginSuccessHandler)            "+
            "   .failureHandler(loginFailureHandler)            "+
            "   .and()                                          "+
            ".logout()                                          "+
            "    .permitAll()                                   "+
            "    .logoutRequestMatcher(new AntPathRequestMatcher(\"/login\", \"DELETE\"))   "+
            "    .logoutSuccessHandler(logoutSuccessHandler)                                "+
            "    .deleteCookies(\"JSESSIONID\")                                         "+
            "    .invalidateHttpSession(true)                                           "+
            "    .and()                                                                 "+
            ".sessionManagement()                                                       "+
            "   .enableSessionUrlRewriting(true)                                        "+
            "   .maximumSessions(1);                                                        ");         

    compiledClass.toClass();

但是代码在启动时失败了,

javassist.CannotCompileException: [source error] authorizeRequests() not found in org.springframework.security.config.annotation.web.HttpSecurityBuilder

它正在 class HTTPSecurityBuilder 中寻找 authorizeRequests(),但它实际上必须查看 class "HttpSecurity"。我怎样才能解决这个问题?提前致谢。

Javassist 不支持泛型,只尊重任何方法的擦除。正如您在 from the javadoc of CsrfConfigurer 中看到的那样,禁用方法是通用的,这就是为什么 Javassist 假设了错误的类型并且无法解析正确的方法。

处理此问题的唯一方法是在 Spring 安全 DSL 的任何通用步骤之后添加适当的类型转换,不幸的是,这几乎是每一步。

如果您正在寻找不受此限制的替代方案,请查看我的库 Byte Buddy,它使用编译代码而不是字符串,并且不受此限制。