spring-security - spring security oauth + redis session,客户端登录时author服务报错

查看:160
本文介绍了spring-security - spring security oauth + redis session,客户端登录时author服务报错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

用spring security的oauth + redis session做服务认证,但在ui跳转到author服务认证后报错,错误信息如下,请问如何解决:

org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.lang.ClassCastException: cannot assign instance of org.springframework.beans.factory.support.StaticListableBeanFactory to field org.springframework.aop.scope.DefaultScopedObject.beanFactory of type org.springframework.beans.factory.config.ConfigurableBeanFactory in instance of org.springframework.aop.scope.DefaultScopedObject
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:81) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
    at org.springframework.data.redis.core.AbstractOperations.deserializeHashValue(AbstractOperations.java:335) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
    at org.springframework.data.redis.core.AbstractOperations.deserializeHashMap(AbstractOperations.java:279) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
    at org.springframework.data.redis.core.DefaultHashOperations.entries(DefaultHashOperations.java:227) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
    at org.springframework.data.redis.core.DefaultBoundHashOperations.entries(DefaultBoundHashOperations.java:102) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
    at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:432) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.session.data.redis.RedisOperationsSessionRepository.onMessage(RedisOperationsSessionRepository.java:519) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.data.redis.listener.RedisMessageListenerContainer.executeListener(RedisMessageListenerContainer.java:249) [spring-data-redis-1.7.2.RELEASE.jar:na]
    at org.springframework.data.redis.listener.RedisMessageListenerContainer.processMessage(RedisMessageListenerContainer.java:239) [spring-data-redis-1.7.2.RELEASE.jar:na]
    at org.springframework.data.redis.listener.RedisMessageListenerContainer$1.run(RedisMessageListenerContainer.java:967) [spring-data-redis-1.7.2.RELEASE.jar:na]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_74]
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.lang.ClassCastException: cannot assign instance of org.springframework.beans.factory.support.StaticListableBeanFactory to field org.springframework.aop.scope.DefaultScopedObject.beanFactory of type org.springframework.beans.factory.config.ConfigurableBeanFactory in instance of org.springframework.aop.scope.DefaultScopedObject
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:79) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
    ... 10 common frames omitted
Caused by: java.lang.ClassCastException: cannot assign instance of org.springframework.beans.factory.support.StaticListableBeanFactory to field org.springframework.aop.scope.DefaultScopedObject.beanFactory of type org.springframework.beans.factory.config.ConfigurableBeanFactory in instance of org.springframework.aop.scope.DefaultScopedObject
    at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2133) ~[na:1.8.0_74]
    at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1305) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2006) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1707) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:501) ~[na:1.8.0_74]
    at org.springframework.aop.framework.AdvisedSupport.readObject(AdvisedSupport.java:557) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_74]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_74]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_74]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_74]
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1058) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1900) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[na:1.8.0_74]
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) ~[na:1.8.0_74]
    at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:70) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:73) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    ... 12 common frames omitted

author服务代码如下
application.yml

server:
  address: 127.0.0.1
  port: 9001
  context-path: /uaa

spring:
  redis:
    host: 192.168.1.190

  freemarker:
    suffix: .html
    cache: false

security:
  oauth2:
    client:
      client-id: app
      client-secret: 1
      scope: openid
      auto-approve-scopes: .*
    authorization:
      check-token-access: permitAll()

  user:
    name: z
    password: 1

AppAuth.java

@SpringBootApplication
@EnableAuthorizationServer
@RestController
@EnableRedisHttpSession
public class AppAuth {

    public static void main(String[] args) {
        SpringApplication.run(AppAuth.class, args);
    }

    @RequestMapping("/user")
    public Principal user(Principal user) {
        return user;
    }

    @Configuration
    @Order(-20)
    static class ConfigSecurity extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .formLogin().loginPage("/login").permitAll()
                    .and()
                    .requestMatchers()
                    .antMatchers("/", "/login", "/oauth/authorize", "/oauth/confirm_access")
                    .and()
                    .authorizeRequests()
                    .anyRequest().authenticated();

        }
    }

    @Configuration
    static class ConfigMvc extends WebMvcConfigurerAdapter {
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("login").setViewName("login");
            registry.addViewController("/").setViewName("hello");
        }
    }
}

login.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<form name="f" action="/uaa/login" method="post">
    <h2>please login</h2>
    <label for="username">username:</label>
    <input type="text" id="username" name="username" value="z">
    <label for="password">password:</label>
    <input type="password" id="password" name="password" value="1">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
    <button type="submit">sign in</button>
</form>
</body>
</html>

ui服务代码如下

application.yml

auth-server: http://localhost:9001/uaa
server:
  address: 127.0.0.1
  port: 9002
  context-path: /ui

spring:
  redis:
    host: 192.168.1.190
  freemarker:
    suffix: .html
    cache: false

security:
  basic:
    enabled: false
  oauth2:
    client:
      client-id: app
      client-secret: 1
      scope: openid
      access-token-uri: ${auth-server}/oauth/token
      user-authorization-uri: ${auth-server}/oauth/authorize
    resource:
      token-info-uri: ${auth-server}/oauth/check_token

AppUi.java

@SpringBootApplication
@EnableOAuth2Sso
@EnableRedisHttpSession
public class AppUi {

    public static void main(String[] args) {
        SpringApplication.run(AppUi.class, args);
    }

    @RequestMapping("/hello")
    public String index(HttpSession session) {
        return "hello";
    }
}

两个服务引入的包如下
build.gradle

buildscript {
    ext {
        springBootVersion = '1.4.0.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-security'
    compile('org.springframework.boot:spring-boot-starter-freemarker')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile("org.springframework.boot:spring-boot-devtools")
    compile 'org.springframework.security.oauth:spring-security-oauth2'

    compile 'org.springframework.session:spring-session-data-redis'

    testCompile('org.springframework.boot:spring-boot-starter-test')
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.SR4"
    }
}


eclipse {
    classpath {
        containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
        containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
    }
}

解决方案

我今天用spring session用redis来持久化oauth2 server和client的会话,也出现了这个bug。

找了一个早上,根据Dave Syer和众人讨论的结果,我个人理解是spring core底层的DefaulListableBeanFactoryserializationId默认没有指定,spring session在用redis持久化session的时候把DefaulListableBeanFactory也序列化进去,导致反序列的时候出现两个DefaulListableBeanFactory的情况。

讨论的链接

这个问题已经在spring core列为bug,4.3.10后面会修复....不过现在貌似还没出来

在讨论页面下面,Dave Syer给出了临时的解决方案,通过自定义的BeanFactoryPostProcessor来确保各服务端的DefaulListableBeanFactory的serializationId保持一致


private static final String SERIALIZATION_ID = "4086d293-522c-4d25-8485-f1c1f5c09218";

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  if ((beanFactory instanceof DefaultListableBeanFactory)) {
      DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
      dlbf.setSerializationId(SERIALIZATION_ID);
  }

}


这个问题就解决了

这篇关于spring-security - spring security oauth + redis session,客户端登录时author服务报错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆