好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

sprintboot使用spring-security包,缓存内存与redis共存方式

项目修改需求描述

项目需要使用分布式缓存机制,但是使用@Cacheable原始仅配置了内存版的,故此次需要改成redis用以支持多应用模式的。

项目中如果直接改成redis的,存在一个问题。如果内存对象同一类,比如都是String的list对象,存的key值又都是"code",会把缓存给冲掉,所以需要对redis的做后缀处理。又因为只有一个redis服务器,所以需要对缓存做项目的前缀处理。

还希望能支持历史项目,做到内存与redis共存,所以顺便就做了CacheManager处理。

代码

使用到的依赖包

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

<!-- 缓存、权限 -->

< dependency >

     < groupId >org.springframework.boot</ groupId >

     < artifactId >spring-boot-starter-cache</ artifactId >

</ dependency >

< dependency >

     < groupId >org.springframework.boot</ groupId >

     < artifactId >spring-boot-starter-security</ artifactId >

</ dependency >

< dependency >

     < groupId >org.springframework.security</ groupId >

     < artifactId >spring-security-test</ artifactId >

     < scope >test</ scope >

</ dependency >

<!-- json -->

< dependency >

     < groupId >com.alibaba</ groupId >

     < artifactId >fastjson</ artifactId >

     < version >1.2.47</ version >

</ dependency >

<!-- redis -->

< dependency >

     < groupId >org.springframework.data</ groupId >

     < artifactId >spring-data-redis</ artifactId >

</ dependency >

< dependency >

     < groupId >io.lettuce</ groupId >

     < artifactId >lettuce-core</ artifactId >

     < version >5.1.0.M1</ version >

</ dependency >

代码处理

首先如果希望程序支持缓存需要注解

?

1

@EnableCaching

然后在application.yml里增加redis的配置

?

1

2

3

4

5

6

7

8

9

10

11

12

spring:

   application:

     name:app

   redis:

     database: 0

     host: XX.XX.XX.XX

     port: 6379

     password:

     pool:

       max-total: 100

       block-when-exhausted: false

     timeout: 5000

增加一个redis处理类RedisConfig,此处做了redis前缀的处理

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cache.concurrent.ConcurrentMapCacheManager;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.Primary;

import org.springframework.core.env.Environment;

import org.springframework.data.redis.cache.RedisCacheConfiguration;

import org.springframework.data.redis.cache.RedisCacheManager;

import org.springframework.data.redis.connection.RedisConnectionFactory;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import org.springframework.data.redis.serializer.RedisSerializationContext;

import org.springframework.data.redis.serializer.RedisSerializer;

import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;

import com.fasterxml.jackson.annotation.PropertyAccessor;

import com.fasterxml.jackson.databind.ObjectMapper;

 

@Configuration

public class RedisConfig { 

     @Autowired

     private Environment env; 

 

     @Bean

     public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

         // 为了开发方便,一般使用<String, Object>

         RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

         redisTemplate.setConnectionFactory(redisConnectionFactory);

 

         // Json序列化配置

         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object. class );

         ObjectMapper objectMapper = new ObjectMapper();

         objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

         objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

         jackson2JsonRedisSerializer.setObjectMapper(objectMapper);       

         StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

 

         // 设置key的序列化方式

         redisTemplate.setKeySerializer(stringRedisSerializer);

         // 设置hashkey的序列化方式

         redisTemplate.setHashKeySerializer(stringRedisSerializer);

         // 设置value的序列化方式

//        template.setValueSerializer(stringRedisSerializer);

         redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

         // 设置hashvalue的序列化方式

//        template.setHashValueSerializer(stringRedisSerializer);

         redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);       

//        template.setBeanClassLoader(this.getClass().getClassLoader());

//        redisTemplate.afterPropertiesSet();

         return redisTemplate;

     }

     @Bean ( "redisCacheManager" )

     //@Primary

     public RedisCacheManager myRedisCacheManager(RedisConnectionFactory redisConnectionFactory){

         RedisSerializer<String> redisSerializer = new StringRedisSerializer();

 

         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object. class );

         ObjectMapper om = new ObjectMapper();

         om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

         om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

         jackson2JsonRedisSerializer.setObjectMapper(om);    

         String prefixStr = env.getProperty( "spring.application.name" ) + ":" ;

         if (! 'prod' .equals(env.getActiveProfiles()[ 0 ])) {

             prefixStr += env.getActiveProfiles()[ 0 ]  + ":" ;

         }

        

         // 配置序列化(解决乱码的问题)

//        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(this.getClass().getClassLoader())

         RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()

//              .computePrefixWith(cacheName -> env.getProperty("spring.application.name").concat(":")

//                      .concat(env.getActiveProfiles()[0])

//                      .concat(":")

//                      .concat(cacheName))

                 .prefixKeysWith(prefixStr)

                 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))

                 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))

                 .disableCachingNullValues();

 

         RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();

         return cacheManager;

     }

 

     @Bean ( "defaultCacheManager" )

     @Primary

     public ConcurrentMapCacheManager cacheManager() {

         ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();

         return cacheManager;

     }  

}

注:RedisCacheManager 和 RedisTemplate 里的json处理要注意一致性。

这边配置了2个cacheManager:(ConcurrentMapCacheManager 默认缓存、RedisCacheManager redis缓存)

必须要默认一个cacheManager,哪个是默认的就在哪个bean上加注解@Primary

如果不写会报下列错误:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
19:42:21.462 [restartedMain] ERROR o.s.b.SpringApplication:858 - Application run failed
java.lang.IllegalStateException: No CacheResolver specified, and no unique bean of type CacheManager found. Mark one as primary or declare a specific CacheManager to use.
at org.springframework.cache.interceptor.CacheAspectSupport.afterSingletonsInstantiated(CacheAspectSupport.java:223)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:866)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

增加MyKeyGenerator,做redis后缀处理

CachingConfigurerSupport 这个接口默认就有@Primary功能,无需额外配置

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.cache.annotation.CacheEvict;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.cache.annotation.CachingConfigurerSupport;

import org.springframework.cache.interceptor.KeyGenerator;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

 

@Configuration

public class MyKeyGeneratorConfig extends CachingConfigurerSupport {

     private final Logger logger = LoggerFactory.getLogger( this .getClass());

     @Bean

//    @Primary

//    @Override

     public KeyGenerator myKeyGenerator() {

         return new KeyGenerator() {

             @Override

             public Object generate(Object target, Method method, Object... params) {

//                String re= String.format("%s::%s(%s)",target.getClass().getName(),method.getName(),

//                        CollectionUtils.arrayToList(params));//Arrays.asList(params)

                

                 StringBuilder sb = new StringBuilder();

                 String valueStr = null ;

                 if (method.isAnnotationPresent(Cacheable. class )) {

                     Cacheable ca = method.getAnnotation(Cacheable. class );

                     if (ca.value() != null ) {

                         valueStr = ca.value()[ 0 ];

                     }

                 } else if (method.isAnnotationPresent(CacheEvict. class )) {

                     CacheEvict ce = method.getAnnotation(CacheEvict. class );

                     if (ce.value() != null ) {

                         valueStr = ce.value()[ 0 ];

                     }

                 }

                

                 if (valueStr != null ) {

                     sb.append(valueStr + ":" );

                 } else {

                     sb.append(target.getClass().getName() + ":" );

                     sb.append(method.getName() + ":" );

                 }

                 for (Object obj : params) {

                     sb.append(obj.toString() + ":" );

                 }

//              return sb.toString();

                 String re = sb.toString();

                

                

                 logger.debug( "缓存生成的key:{}。" ,re);

                 return re;

             }

         };

     }  

}

缓存类处理:

?

1

2

3

4

@Cacheable (value = "XXX" , keyGenerator = "myKeyGenerator" , cacheManager = "redisCacheManager" )

public List<String> getXXXX(String userCode) {

  XXXXXXXXXX

}

对应的@CacheEvict 记得也把该属性加上,如果不是默认的话: keyGenerator = [myKeyGenerator]

权限类处理:

针对权限类controller增加注解判断,没权限直接报错

?

1

@PreAuthorize ([hasAuthority(‘privileges')])

权限缓存加载类:

?

1

2

3

4

5

@Cacheable ( "privileges" )

private List<GrantedAuthority> makeAuth(String userCode) {

  List<MyGrantedAuthority> privileges = XXX;

  return privileges;

}

权限类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.SpringSecurityCoreVersion;

import org.springframework.util.Assert;

public class MyGrantedAuthority  implements GrantedAuthority {

     private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

     private String authority;  

     public MyGrantedAuthority() {

         super ();

     }

 

     public MyGrantedAuthority(String authority) {

         Assert.hasText(authority, "A granted authority textual representation is required" );

         this .authority = authority;

     }

 

     @Override

     public String getAuthority() {

         return authority;

     }

 

     @Override

     public boolean equals(Object obj) {

         if ( this == obj) {

             return true ;

         }

 

         if (obj instanceof MyGrantedAuthority) {

             return authority.equals(((MyGrantedAuthority) obj).authority);

         }

 

         return false ;

     }

 

     @Override

     public int hashCode() {

         return this .authority.hashCode();

     }

 

     @Override

     public String toString() {

         return this .authority;

     }

}

异常问题解决

如果项目中存在LocalDateTime会报错:

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])
[truncated 981 bytes]; line: 1, column: 360] (through reference chain: ["createdTime"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1452)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1028)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:116)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromAny(AsArrayTypeDeserializer.java:71)
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:712)
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3129)
at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:73)
... 112 common frames omitted

需要对类里面的LocalDateTime增加注解

?

1

2

3

4

5

6

7

8

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;

import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;

 

     @JsonSerialize (using = LocalDateTimeSerializer. class )

     @JsonDeserialize (using = LocalDateTimeDeserializer. class )

  private LocalDateTime XXX;

如不存在jsr310的包可以增加pom配置

?

1

2

3

4

5

6

<!-- 缓存、权限 -->

       < dependency >

           < groupId >com.fasterxml.jackson.datatype</ groupId >

           < artifactId >jackson-datatype-jsr310</ artifactId >

           < version >2.9.8</ version >

       </ dependency >

UserDetails子类代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.userdetails.UserDetails;

//import com.fasterxml.jackson.annotation.JsonIgnore;

public class JwtUser implements UserDetails {

     private String username;

     private String userCode;

     private String password;

     private Collection<? extends GrantedAuthority> authorities;

     private Boolean enabled;

     private Boolean accountNonExpired = true ;

     private Boolean accountNonLocked = true ;

     private Boolean credentialsNonExpired = true ;  

     public JwtUser() {

         super ();

     }

     String getPassword();

     ...

     ...

     ...

}

这边需要写一个无参数构造函数,因为json反序列化原因

UserDetails 这个里面对应getXXX(例如getPassword)的对象都要写对应的参数,否则json转义的时候会报错,如果用不到就增加注解@JsonIgnore。

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized field "accountNonLocked" ]; line: 1, column: 18401] (through reference chain: JwtUser["accountNonLocked"])
at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:75)
at org.springframework.data.redis.serializer.DefaultRedisElementReader.read(DefaultRedisElementReader.java:48)
at org.springframework.data.redis.serializer.RedisSerializationContext$SerializationPair.read(RedisSerializationContext.java:226)
at org.springframework.data.redis.cache.RedisCache.deserializeCacheValue(RedisCache.java:254)
at org.springframework.data.redis.cache.RedisCache.lookup(RedisCache.java:88)
at org.springframework.cache.support.AbstractValueAdaptingCache.get(AbstractValueAdaptingCache.java:58)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:73)
at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:554)
at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:519)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:401)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:345)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:451)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
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.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
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:107)
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:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)

权限类异常

使用SimpleGrantedAuthority会因无参数构造函数报错,因为json反序列化原因,需要重新建一个子类,并且增加无参数构造函数,类名为MyGrantedAuthority(此类上面详细代码已写,故不重复写了)。

报错内容

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `org.springframework.security.core.authority.SimpleGrantedAuthority` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"["XXX["authorities"]->java.util.ArrayList[0])
at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:75)
at org.springframework.data.redis.serializer.DefaultRedisElementReader.read(DefaultRedisElementReader.java:48)
at org.springframework.data.redis.serializer.RedisSerializationContext$SerializationPair.read(RedisSerializationContext.java:226)
at org.springframework.data.redis.cache.RedisCache.deserializeCacheValue(RedisCache.java:254)
at org.springframework.data.redis.cache.RedisCache.lookup(RedisCache.java:88)
at org.springframework.cache.support.AbstractValueAdaptingCache.get(AbstractValueAdaptingCache.java:58)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:73)
at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:554)
at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:519)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:401)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:345)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:451)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
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.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
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:107)
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:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/weixin_47136046/article/details/113133595

查看更多关于sprintboot使用spring-security包,缓存内存与redis共存方式的详细内容...

  阅读:14次