Spring Boot 3.0.2 出现奇怪的安全错误

问题描述 投票:0回答:1

我在 Spring Boot 3.0.2 中遇到了一个非常奇怪的安全问题

当我尝试使用

@PreAuthorize
保护 REST 服务并且该方法包含参数时,我收到以下错误消息:

Name for argument of type [int] not specified, and parameter name information not found in class file either.

如果我删除注释,一切都会恢复正常。

这是我的源代码:

这项工作,方法 listAll 上没有参数:

@RestController
@RequestMapping("/api/currency")
@PreAuthorize("hasAnyRole('api','frontend')")  // <<--
public class CurrencyRestService {

    @GetMapping("/")
    public Page<Currency> listAll() { // <<--
        return currencyController.listAll(0, 100);
    }
}

这个也能用,没有PreAuthorize,但是有参数

@RestController
@RequestMapping("/api/currency")
//@PreAuthorize("hasAnyRole('api','frontend')") // <<--
public class CurrencyRestService {

    @GetMapping("/")
    public Page<Currency> listAll(@RequestParam(defaultValue = "0") int page,      // <<--
                                  @RequestParam(defaultValue = "100") int size) {  // <<--
        return currencyController.listAll(page, size);
    }
}

这行不通:

@RestController
@RequestMapping("/api/currency")
@PreAuthorize("hasAnyRole('api','frontend')")  // <<--
public class CurrencyRestService {

    @GetMapping("/")
    public Page<Currency> listAll(@RequestParam(defaultValue = "0") int page,      // <<--
                                  @RequestParam(defaultValue = "100") int size) {  // <<--
        return currencyController.listAll(page, size);
    }
}

我不知道我能做什么?有人有想法吗?

我的安全过滤器链:

http.securityMatcher("/api/**")
            .oauth2ResourceServer()
            .jwt()
            .jwtAuthenticationConverter(authenticationConverter);

http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

http.csrf().disable();

http.securityMatcher("/api/**")
            .authorizeHttpRequests()
                .requestMatchers("/api/**")
                .authenticated();
http.build();

编辑:

这也不行:

@RestController
@RequestMapping("/api/currency")
@PreAuthorize("hasAnyRole('api','frontend')")  // <<--
public class CurrencyRestService {

    @GetMapping("/")
    public Page<Currency> listAll(@RequestParam(defaultValue = "0",
                                                name = "page") int page,      // <<--
                                  @RequestParam(defaultValue = "100",
                                                name = "size") int size) {  // <<--
        return currencyController.listAll(page, size);
    }
}

还有 javac Parameter -g:vars 和/或 -parameters 没有帮助

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <forceJavacCompilerUse>true</forceJavacCompilerUse>
        <compilerArgs>
            <arg>-g:vars</arg>
            <arg>-parameters</arg>
        </compilerArgs>
        <source>${maven.compiler.source}</source>
        <target>${maven.compiler.target}</target>
    </configuration>
</plugin>

编辑2:

如果我使用@EnableGlobalMethodSecurity,应用程序不会启动。我收到此错误消息:

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException:
Invalid bean definition with name 'metaDataSourceAdvisor' defined in null: Cannot register bean definition
[Root bean: class [org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null]
for bean 'metaDataSourceAdvisor' since there is already 
[Root bean: class [org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null] bound.

完成,我已经有了注释

编辑3:

如果我不使用 @RequestParam 但这样做它会起作用:

@RestController
@RequestMapping("/api/currency")
@PreAuthorize("hasAnyRole('api','frontend')")  // <<--
public class CurrencyRestService {

    @GetMapping("/")
    public Page<Currency> listAll(Map<String, String> reqParam) { // <<--
        int page = 0;
        int size = 100;
        try {
            page = Integer.parseInt(reqParam.get("page"));
            size = Integer.parseInt(reqParam.get("size"));
        } catch (Exception e) {
            page = 0;
            size = 100;
        }
        if (size <= 0) {
            size = 100;
        }
        return currencyController.listAll(page, size);
    }
}

编辑4:

问题更奇怪。如果我现在做一个 POST,那么只有一个完全空的对象到达方法“添加”。当然我得到一个 NotNull 错误。如果我关闭安全性,物品就会干净完整地到达。

@PostMapping("/")
@PreAuthorize("hasAnyRole('api-write','frontend')")
public ResponseEntity add(@RequestBody Currency newObject) {
        System.err.println(newObject.toString());
        return new ResponseEntity(this.controller.add(newObject), HttpStatus.OK);
}

错误信息:

ConstraintViolationImpl{interpolatedMessage='darf nicht null sein', propertyPath=updatedBy, rootBeanClass=class de.bewidata.framework.entity.zrentity.Currency, messageTemplate='{jakarta.validation.constraints.NotNull.message}'}

发送对象:

{"objectType":"Currency","objectId":"2ea69820-1f8b-46c8-80c1-7e61e2f983fa","objectVersion":0,"createdAt":"2023-03-02T15:44:37.690+01:00","createdBy":"system","updatedAt":"2023-03-02T15:44:37.690+01:00","updatedBy":"system","deleted":false,"deletedAt":null,"deletedBy":null,"deactivated":false,"deactivatedAt":null,"id":0,"name":"Dollar","iso2":null,"iso3":"USD","symbol":"$","alignment":"RIGHT","exchangeRatio":1.00}

安全获取对象:

{"objectType":"Currency","objectId":"2ea69820-1f8b-46c8-80c1-7e61e2f983fa","objectVersion":null,"createdAt":"2023-03-02T15:44:37.690+01:00","createdBy":null,"updatedAt":"2023-03-02T15:44:37.690+01:00","updatedBy":null,"deleted":false,"deletedAt":null,"deletedBy":null,"deactivated":false,"deactivatedAt":null,"id":null,"name":null,"iso2":null,"iso3":null,"symbol":null,"alignment":"RIGHT","exchangeRatio":null}

编辑 5: 我调试请求并发现了差异。我希望能以任何方式提供帮助。如果 Rest Request 工作,没有 Annotaion

@PreAuthorize("hasAnyRole('api','frontend')")
,正确的抽象类进入
MethodParameter
,因此可以找到参数名称。当我添加注释时,错误的 extendet 类在
MethodParameter
中也带有 final,并且找不到名称。

package org.springframework.web.method.annotation;

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {

    private NamedValueInfo getNamedValueInfo(MethodParameter parameter) { // WORK without Security  parameter.executable = public org.springframework.data.domain.Page com.example.framework.AbstractRestService.listAll(int,int)
                                                                          // NOT WORK with Security parameter.executable = public final org.springframework.data.domain.Page com.example.framework.BusinessRoleRestService$$SpringCGLIB$$0.listAll(int,int)
        NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
        if (namedValueInfo == null) {
            namedValueInfo = createNamedValueInfo(parameter);
            namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
            this.namedValueInfoCache.put(parameter, namedValueInfo);
        }
        return namedValueInfo;
    }
}

编辑5:

我能够隔离问题。但是不知道怎么解决。我注意到这个

$$SpringCGLIB$$
代理类只是为插入另一个方法的其余服务类创建的。

这项工作没有问题:

@RestController
@RequestMapping("/api/businessrole")
@Tag(name = "businessrole")
@Extension
@PreAuthorize("hasAnyRole('api','frontend')")
public class BusinessRoleRestService extends AbstractRestService<BusinessRoleController, Long, BusinessRole> {

    public BusinessRoleRestService(BusinessRoleController businessRoleController) {
        super(businessRoleController);
    }
}

在这里创建了

$$SpringCGLIB$$
代理类,我得到了错误消息。

@RestController
@RequestMapping("/api/businessrole")
@Tag(name = "businessrole")
@Extension
@PreAuthorize("hasAnyRole('api','frontend')")
public class BusinessRoleRestService extends AbstractRestService<BusinessRoleController, Long, BusinessRole> {

    public BusinessRoleRestService(BusinessRoleController businessRoleController) {
        super(businessRoleController);
    }

    @ApiResponses(value = {
            @ApiResponse(responseCode = "200",
                         description = "Success")
    })
    @Operation(summary = "",
               description = "")
    @GetMapping("/types")
    public List<String> listAllSubclasses() {
        return this.controller.findAllSubclasses();
    }
}
spring spring-boot spring-security spring-restcontroller spring-rest
1个回答
0
投票

我找到了解决方案。使用

ClassUtils.getUserClass(clazz);
我得到了正确的类,并且可以使用
RequestMappingHandlerMapping
手动注册方法。现在一切正常。我仍然认为这是一个错误。但我不知道在哪里。

© www.soinside.com 2019 - 2024. All rights reserved.