the boot version is 2.5.2, i'm use webflux, i'm use my custom session store, here is my config
@Bean
public WebSessionManager webSessionManager(WebSessionStore sessionStore) {
DefaultWebSessionManager manager = new DefaultWebSessionManager();
manager.setSessionStore(sessionStore);
return manager;
}
when i start my app, it throw an exception
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'webSessionManager', defined in class path resource [org/jasig/cas/client/webflux/autoconfigure/CasAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration$EnableWebFluxConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
when i saw the WebFluxAutoConfiguration, i found
@Bean
@ConditionalOnMissingBean(name = WebHttpHandlerBuilder.WEB_SESSION_MANAGER_BEAN_NAME)
public WebSessionManager webSessionManager() {
DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager();
CookieWebSessionIdResolver webSessionIdResolver = new CookieWebSessionIdResolver();
webSessionIdResolver.addCookieInitializer((cookie) -> cookie
.sameSite(this.webFluxProperties.getSession().getCookie().getSameSite().attribute()));
webSessionManager.setSessionIdResolver(webSessionIdResolver);
return webSessionManager;
}
the bean is already defined, i guess the WebFluxAutoConfiguration may execute before my code and register the bean. please provider a WebSessionManageBuilderCustomizer(like jackson) for me to config the WebSessionManager
Comment From: cjdxhjj
the old release is working.
Comment From: snicoll
I have moved this issue to the appropriate issue tracker and I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.
Comment From: cjdxhjj
thanks very much,
Comment From: snicoll
I am a little bit confused. Are you responsible of CasAutoConfiguration or is that a third-party starter you're using? The exception is about that one, not any used defined code.
Comment From: cjdxhjj
i have wrote a thrid part webflux cas client, in that client ,i save session in redis, and provide a starter
Comment From: cjdxhjj
my starter is here
@Configuration
@EnableConfigurationProperties(CasProperties.class)
public class CasAutoConfiguration {
private CasProperties casProperties;
private Environment environment;
private XmlMapper mapper = new XmlMapper();
private WebClient webClient;
public CasAutoConfiguration(CasProperties casProperties, Environment environment) {
this.casProperties = casProperties;
this.environment = environment;
HttpClient httpClient = HttpClient.create().option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 500).doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler(1)).addHandlerLast(new WriteTimeoutHandler(1)));
this.webClient = WebClient.builder().baseUrl(casProperties.getCasBaseUrl()).clientConnector(new ReactorClientHttpConnector(httpClient)).build();
}
@Bean
public WebSessionStore sessionStore(ISessionRepository sessionRepository) {
return new CasSessionStore(sessionRepository);
}
@Bean(destroyMethod = "destroy")
public ISessionRepository sessionRepository(RedisClient redisClient) {
return new LuttuceRedisSessionRepository(redisClient, environment.getProperty("spring.application.name"), Duration.parse(environment.getProperty("spring.session.timeout", "PT30M")), casProperties.getClassList(), casProperties.getSerializerMap());
}
@Bean
public RedirectPolicy redirectPolicy(CasProperties casProperties) {
return new RedirectPolicy(casProperties.getCasBaseUrl(), casProperties.getLoginUrlPc(), casProperties.getLoginUrlMob(), casProperties.isUseDefLogin(), casProperties.getSystemId());
}
@Bean
public RedisClient redisClient() {
RedisURI.Builder builder = RedisURI.builder().withHost(environment.getProperty("spring.redis.host")).withPort(Integer.parseInt(environment.getProperty("spring.redis.port", "6379")));
String password = environment.getProperty("spring.redis.password");
if(password != null) {
builder.withPassword(password.toCharArray());
}
String ssl = environment.getProperty("spring.redis.ssl");
if(ssl != null) {
builder.withSsl(Boolean.parseBoolean(ssl));
}
String timeout = environment.getProperty("spring.redis.timeout");
if(timeout != null) {
builder.withTimeout(Duration.ofMillis(Long.parseLong(timeout)));
}
builder.withDatabase(Integer.parseInt(environment.getProperty("spring.redis.database")));
return RedisClient.create(builder.build());
}
@Bean
@Order(1)
public WebFilter singleSignOutFilter(ISessionRepository sessionRepository) {
return new SingleSignOutFilter(sessionRepository, mapper);
}
@Bean
@Order(2)
public WebFilter authenticationFilter(ISessionRepository sessionRepository, ObjectMapper objectMapper, RedirectPolicy redirectPolicy, CasProperties casProperties){
List<ILoginHandler> handlers = new ArrayList<>();
handlers.add(new CookieRefreshLoginHandler(sessionRepository, casProperties.getCasCookiePrefix()));
handlers.add(new ZntLoginHandler(webClient, objectMapper));
handlers.add(new UcTicketLoginHandler(webClient, objectMapper, casProperties.getCasCookiePrefix()));
handlers.add(new AjaxLoginHandler());
handlers.add(new TicketLoginHandler(mapper, webClient, redirectPolicy));
handlers.add(new WxMiniAppLoginHandler(casProperties.getWxMiniProgRedirectUrl()));
handlers.add(new WxGzhLoginHandler(casProperties.getWxAppId(), casProperties.getWxAppNo(), casProperties.getWxLoginUrl(), casProperties.getSystemId(), casProperties.getWxScope()));
handlers.add(new AliGzhLoginHandler(casProperties.getAliAppId(), casProperties.getAliLoginUrl(), casProperties.getAliScope(), casProperties.getSystemId()));
handlers.add(new DefaultLoginHandler(redirectPolicy));
return new AuthenticationFilter(casProperties.getAuthenticationUrl(), casProperties.getAuthenticationExcludeUrl(), handlers);
}
@Bean
@Order(3)
public WebFilter assertionFilter(CasProperties casProperties, ObjectMapper objectMapper) {
List<ILoginHandler> handlers = new ArrayList<>();
handlers.add(new SilenceZntLoginHandler(webClient, objectMapper));
handlers.add(new SilenceUcTicketLoginHandler(webClient, objectMapper, casProperties.getCasCookiePrefix()));
return new AssertionFilter(casProperties.getAssertionUrl(), handlers);
}
@Bean
public WebSessionManager webSessionManager(WebSessionStore sessionStore) {
DefaultWebSessionManager manager = new DefaultWebSessionManager();
manager.setSessionStore(sessionStore);
return manager;
}
}
Comment From: snicoll
@cjdxhjj Spring Session works by letting users configure a custom store in the user-configuration. If you do this in an auto-configuration, you need to run this one before ours so that your changes are applied before ours. @AutoConfigureBefore(WebFluxAutoConfiguration.class) should do it.
Having said that, being able to tune the store without replacing everything else sounds an interesting idea.
Comment From: cjdxhjj
i have mention that,
the bean is already defined, i guess the WebFluxAutoConfiguration may execute before my code and register the bean. please provider a WebSessionManageBuilderCustomizer(like jackson) for me to config the WebSessionManager
add @AutoConfigureBefore(WebFluxAutoConfiguration.class) should work, if the framework provider a Customizer may it be better
Comment From: cjdxhjj
when you enhance that class, and provider many option. when it defined by user, it may cause many other errors
Comment From: weixsun
@cjdxhjj
please provider a WebSessionManageBuilderCustomizer(like jackson) for me to config the WebSessionManager
WebSessionManager is an interface, which is slightly different from jackson configuration.
Even if *Customizer is provided, DefaultWebSessionManagerBuilderCustomizer should be provided instead of WebSessionManageBuilderCustomizer, because both WebSessionIdResolver and WebSessionStore are DefaultWebSessionManager fields.
@snicoll
https://github.com/spring-projects/spring-boot/blob/0f20c236dacd29f39af689d35a22b1d5e156a5d0/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java#L312
Maybe we can customize WebSessionStore like custom WebSessionIdResolver, The only thing that may need to be noted is that the current spring-session does not support injection of WebSessionStore(Consider the situation that save the session to a non-local env), Considering this, maybe spring-session also needs to do appropriate enhancement work
https://github.com/spring-projects/spring-session/blob/33993b2ff6671257bd5d643ae660d01eaaae6189/spring-session-core/src/main/java/org/springframework/session/config/annotation/web/server/SpringWebSessionConfiguration.java#L56
@Bean(WebHttpHandlerBuilder.WEB_SESSION_MANAGER_BEAN_NAME)
public WebSessionManager webSessionManager(ReactiveSessionRepository<? extends Session> repository) {
SpringSessionWebSessionStore<? extends Session> sessionStore = new SpringSessionWebSessionStore<>(repository);
DefaultWebSessionManager manager = new DefaultWebSessionManager();
Comment From: cjdxhjj
thanks very much, inject the ObjectProvider is another good way to do the work, the Customizer should allowed set part of field
Comment From: wilkinsona
We’re cleaning out the issue tracker and closing issues that we’ve not seen much demand to fix. Feel free to comment with additional justifications if you feel that this one should not have been closed.