对接口权限校验类ApiScopePermissionHandler进行扩展改造,如何解决依赖冲突的问题

Blade 已结 1 1034
cy_bladex
cy_bladex 剑圣 2021-03-04 09:26

一、该问题的重现步骤是什么?

1.ApiScopePermissionHandler和BladePermissionHandler都实现了IPermissionHandler这个接口,我对ApiScopePermissionHandler进行了改造,需要怎样配置才能让接口鉴权走ApiScopePermissionHandler里面的逻辑,在哪些模块引入blade-scope-api?另外业务子系统是新建的,子系统业务使用自己独立的数据库,鉴权还是走的gateway。

启动登录时,报了sql错误。


改造的代码如下:

1.首先修改了ApiScopePermissionHandler类中的两个方法

image.png

2.ApiScopeCache中的代码也相应进行了修改,增加userPermissionCode方法

image.png

3.ApiScopeClient中的userPermissionCode方法

image.png

4.scopePermissionStatement方法,注意sql的表是另外自定义的api权限表,这个权限报在bladex数据库中

image.png



5.在blade-auth/pom.xml文件中引入blade-scope-api模块

image.png


6.启动,调用/blade-auth/oauth/token接口获取token登录时,授权模块后台报了sql错误

image.png

二、你期待的结果是什么?实际看到的又是什么?

期待结果是:对接口权限校验类进行扩展改造,使用自定义的api权限表,并对使用独立数据库的业务子系统接口进行接口鉴权。

实际情况是:改造后auth模块引入的blade-scope-api其依赖中有blade-core-secure 依赖,会与auth依赖的secure冲突,报Table 'bladex.oauth_client_details' doesn't exist,那么怎个问题怎么解决?


三、你正在使用的是什么产品,什么版本?在什么操作系统上?

saber,bladex商业版 2.7.0.REALEASE,win10

四、请提供详细的错误堆栈信息,这很重要。


org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove from oauth_client_details where client_id = ?]; nested exception is java.sql.SQLSyntaxErrorException: Table 'bladex.oauth_client_details' doesn't exist

        at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:239)

        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)

        at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1443)

        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633)

        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669)

        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:700)

        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:712)

        at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:790)

        at org.springframework.security.oauth2.provider.client.JdbcClientDetailsService.loadClientByClientId(JdbcClientDetailsService.java:119)

        at org.springblade.auth.service.BladeClientDetailsServiceImpl.loadClientByClientId(BladeClientDetailsServiceImpl.java:45)

        at org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService.loadUserByUsername(ClientDetailsUserDetailsService.java:47)

        at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:108)

        at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144)

        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175)

        at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:169)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)

        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)

        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)

        at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)

        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)

        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)

        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)

        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)

        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)

        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)

        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)

        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)

        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)

        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)

        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)

        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)

        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)

        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)

        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)

        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)

        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)

        at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)

        at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)

        at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)

        at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)

        at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)

        at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:111)

        at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)

        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)

        at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)

        at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)

        at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)

        at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)

        at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)

        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)

        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)

        at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)

        at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)

        at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)

        at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)

        at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)

        at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)

        at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)

        at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)

        at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)

        at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)

        at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)

        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

        at java.lang.Thread.run(Thread.java:745)

Caused by: java.sql.SQLSyntaxErrorException: Table 'bladex.oauth_client_details' doesn't exist

        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)

        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)

        at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)

        at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)

        at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003)

        at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227)

        at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:678)

        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)

        ... 77 more

五、若有更多详细信息,请在下面提供。

尝试将blade-core-secure包排除之后,auth工程启动会报错

image.png

java.lang.IllegalArgumentException: Could not find class [org.springblade.core.secure.config.RegistryConfiguration]

        at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:334) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.core.annotation.TypeMappedAnnotation.adapt(TypeMappedAnnotation.java:446) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.core.annotation.TypeMappedAnnotation.getValue(TypeMappedAnnotation.java:369) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.core.annotation.TypeMappedAnnotation.asMap(TypeMappedAnnotation.java:284) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.core.annotation.AbstractMergedAnnotation.asAnnotationAttributes(AbstractMergedAnnotation.java:193) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.core.type.AnnotatedTypeMetadata.getAnnotationAttributes(AnnotatedTypeMetadata.java:106) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.annotation.AnnotationConfigUtils.attributesFor(AnnotationConfigUtils.java:285) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.annotation.AnnotationBeanNameGenerator.determineBeanNameFromAnnotation(AnnotationBeanNameGenerator.java:102) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.annotation.AnnotationBeanNameGenerator.generateBeanName(AnnotationBeanNameGenerator.java:81) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.registerBeanDefinitionForImportedConfigurationClass(ConfigurationClassBeanDefinitionReader.java:160) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:141) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:280) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:707) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.12.RELEASE.jar:2.2.12.RELEASE]

        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.12.RELEASE.jar:2.2.12.RELEASE]

        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405) ~[spring-boot-2.2.12.RELEASE.jar:2.2.12.RELEASE]

        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.12.RELEASE.jar:2.2.12.RELEASE]

        at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:140) [spring-boot-2.2.12.RELEASE.jar:2.2.12.RELEASE]

        at org.springblade.core.launch.BladeApplication.run(BladeApplication.java:50) [blade-core-launch-2.7.1.RELEASE.jar:na]

        at org.springblade.auth.AuthApplication.main(AuthApplication.java:34) [classes/:na]

Caused by: java.lang.ClassNotFoundException: org.springblade.core.secure.config.RegistryConfiguration

        at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_101]

        at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_101]

        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_101]

        at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_101]

        at java.lang.Class.forName0(Native Method) ~[na:1.8.0_101]

        at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_101]

        at org.springframework.util.ClassUtils.forName(ClassUtils.java:284) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:324) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]

        ... 24 common frames omitted


1条回答
  •  admin
    admin (最佳回答者)
    2021-03-04 22:36

    主要问题在于blade-scope-api需要依赖blade-core-secure,而blade-core-secure又与blade-auth冲突,因为blade-auth依赖了security。但删除blade-core-secure依赖后,blade-scope-api本身又会报错。


    所以正确的做法应该是这样:

     1. blade-auth只用于外部业务模块的feign引入调用

     2. 不引入blade-scope-api来做业务数据过滤

     3. 应该是把blade-scope-api给其他业务工程依赖,然后业务工程对应的api工程参考blade-user-api对外开放feign接口

     4. blade-auth引入业务feign,进行调用

     5. 业务feign调用后会转到业务工程的controller实现,而业务工程引入了blade-scope-api,会自动进行数据权限的加载

     6. 而对于一些需要独立数据库的服务,也可以引入blade-scope-api,因为blade-scope-api底层也是feign的形式前往blade-system获取数据并返回配置

     7. 这样的话你的问题就可以解决了


    作者追问:2021-03-04 22:36

    目的主要是想直接用项目中的@PreAuth("hasPermission('xxx:xxx:xxx')")这个注解对子系统进行接口权限校验,按照解决方案进行修改的话,子工程的接口鉴权拦截也会调用自定义的hasPermission方法么?

    作者追问:2021-03-04 22:36

    子工程会调用的,只要不把这个注解写在blade-auth就行。具体实现方式可以看blade-core-secure的相关源码

    0 讨论(1)
提交回复