Skip to content

SpringSessionWebSessionStore createSession is not related to WebSessionIdResolver ? #1148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
czarea opened this issue Aug 7, 2018 · 4 comments
Assignees
Labels
for: stack-overflow A question that's better suited to stackoverflow.com

Comments

@czarea
Copy link

czarea commented Aug 7, 2018

SpringSessionWebSessionStore only has the createSession method, and does not provide createSession(String id). The session id obtained by executing createSession has nothing to do with WebSessionIdResolver, but is generated directly by UUID. So I have no meaning in defining WebSessionIdResolver, it only works for getting session, but it has nothing to do with creating session.

@vpavic vpavic self-assigned this Aug 8, 2018
@vpavic
Copy link
Contributor

vpavic commented Aug 8, 2018

I'm not sure I understand the problem you're having @vernezhou. Could you provide an example that demonstrates the problem?

@vpavic vpavic added the status: waiting-for-feedback We need additional information before we can continue label Aug 8, 2018
@czarea
Copy link
Author

czarea commented Aug 9, 2018

Sorry!
I want to know how to develop the sessionid generation strategy in SpringSessionWebSessionStore. I created my own WebSessionIdResolver, but it only works when I get the WebSession. It doesn't work create the Websession.

import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import org.springframework.http.HttpCookie;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.session.WebSessionIdResolver;

/**
 * <pre>
 *     See https://docs.spring.io/spring-session/docs/current/reference/html5/
 * </pre>
 *
 * {@link org.springframework.session.web.http.CookieHttpSessionIdResolver}
 *
 */
public class MySessionIdResolver implements WebSessionIdResolver {

    /**
     * Default value for {@link #setHeaderName(String)}.
     */
    public static final String DEFAULT_HEADER_NAME = "SESSION";


    private String headerName = DEFAULT_HEADER_NAME;


    /**
     * Set the name of the session header to use for the session id. The name is used to extract the
     * session id from the request headers as well to set the session id on the response headers.
     * <p>By default set to {@code DEFAULT_HEADER_NAME}
     *
     * @param headerName the header name
     */
    public void setHeaderName(String headerName) {
        Assert.hasText(headerName, "'headerName' must not be empty");
        this.headerName = headerName;
    }

    /**
     * Return the configured header name.
     *
     * @return the configured header name
     */
    public String getHeaderName() {
        return this.headerName;
    }


    @Override
    public List<String> resolveSessionIds(ServerWebExchange exchange) {
        MultiValueMap<String, HttpCookie> cookies = exchange.getRequest().getCookies();
        List<String> matchingCookieValues = new ArrayList<>();
        List<HttpCookie> session = cookies.get(this.headerName);
        if (session != null && !session.isEmpty()) {
            session.forEach(httpCookie -> {
                String cookieValue = httpCookie.getValue();
                String sessionId = base64Decode(cookieValue);
                if (sessionId == null) {
                    sessionId = cookieValue;
                }
                matchingCookieValues.add(sessionId);
            });

        }

        return matchingCookieValues;
    }

    /**
     * Decode the value using Base64.
     *
     * @param base64Value the Base64 String to decode
     * @return the Base64 decoded value
     * @since 1.2.2
     */
    private String base64Decode(String base64Value) {
        try {
            byte[] decodedCookieBytes = Base64.getDecoder().decode(base64Value);
            return new String(decodedCookieBytes);
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public void setSessionId(ServerWebExchange exchange, String id) {
        exchange.getResponse().getHeaders().set(getHeaderName(), id);
    }

    @Override
    public void expireSession(ServerWebExchange exchange) {
        this.setSessionId(exchange, "");
    }
}


The createSession() method in the SpringSessionWebSessionStore class has nothing to do with the WebSessionIdResolver.

/**
 * The {@link WebSessionStore} implementation that provides the {@link WebSession}
 * implementation backed by a {@link Session} returned by the
 * {@link ReactiveSessionRepository}.
 *
 * @param <S> the {@link Session} type
 * @author Rob Winch
 * @author Vedran Pavic
 * @since 2.0
 */
public class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore {

	private final ReactiveSessionRepository<S> sessions;

	private Clock clock = Clock.system(ZoneOffset.UTC);

	public SpringSessionWebSessionStore(ReactiveSessionRepository<S> reactiveSessionRepository) {
		Assert.notNull(reactiveSessionRepository, "reactiveSessionRepository cannot be null");
		this.sessions = reactiveSessionRepository;
	}

	/**
	 * Configure the {@link Clock} to use to set lastAccessTime on every created
	 * session and to calculate if it is expired.
	 * <p>This may be useful to align to different timezone or to set the clock
	 * back in a test, e.g. {@code Clock.offset(clock, Duration.ofMinutes(-31))}
	 * in order to simulate session expiration.
	 * <p>By default this is {@code Clock.system(ZoneId.of("GMT"))}.
	 * @param clock the clock to use
	 */
	public void setClock(Clock clock) {
		Assert.notNull(clock, "clock cannot be null");
		this.clock = clock;
	}

	@Override
	public Mono<WebSession> createWebSession() {
		return this.sessions.createSession().map(this::createSession);
	}
       ......

Get a WebSession through the DefaultWebSessionManager is associated with the WebSessionIdResolver

/**
 * Default implementation of {@link WebSessionManager} delegating to a
 * {@link WebSessionIdResolver} for session id resolution and to a
 * {@link WebSessionStore}
 *
 * @author Rossen Stoyanchev
 * @author Rob Winch
 * @since 5.0
 */
public class DefaultWebSessionManager implements WebSessionManager {

	private WebSessionIdResolver sessionIdResolver = new CookieWebSessionIdResolver();

	private WebSessionStore sessionStore = new InMemoryWebSessionStore();


	/**
	 * Configure the id resolution strategy.
	 * <p>By default an instance of {@link CookieWebSessionIdResolver}.
	 * @param sessionIdResolver the resolver to use
	 */
	public void setSessionIdResolver(WebSessionIdResolver sessionIdResolver) {
		Assert.notNull(sessionIdResolver, "WebSessionIdResolver is required");
		this.sessionIdResolver = sessionIdResolver;
	}

	/**
	 * Return the configured {@link WebSessionIdResolver}.
	 */
	public WebSessionIdResolver getSessionIdResolver() {
		return this.sessionIdResolver;
	}

	/**
	 * Configure the persistence strategy.
	 * <p>By default an instance of {@link InMemoryWebSessionStore}.
	 * @param sessionStore the persistence strategy to use
	 */
	public void setSessionStore(WebSessionStore sessionStore) {
		Assert.notNull(sessionStore, "WebSessionStore is required");
		this.sessionStore = sessionStore;
	}

	/**
	 * Return the configured {@link WebSessionStore}.
	 */
	public WebSessionStore getSessionStore() {
		return this.sessionStore;
	}


	@Override
	public Mono<WebSession> getSession(ServerWebExchange exchange) {
		return Mono.defer(() -> retrieveSession(exchange)
				.switchIfEmpty(this.sessionStore.createWebSession())
				.doOnNext(session -> exchange.getResponse().beforeCommit(() -> save(exchange, session))));
	}
        ......

@vpavic vpavic added for: stack-overflow A question that's better suited to stackoverflow.com and removed status: waiting-for-feedback We need additional information before we can continue labels Aug 9, 2018
@vpavic
Copy link
Contributor

vpavic commented Aug 9, 2018

Thanks for following up @vezhou. OK, so your concern is actually the generation of session id.

As stated in the WebSessionIdResolver javadoc, its purpose is to correlate the incoming HTTP request to session. So the creation of new sessions (and by extension, the session id generation) in not among its responsibilities.

Session id is actually generated by the underlying SessionRepository or ReactiveSessionRepository implementation. Spring Session currently uses UUID based session id's (as all the repo implementations delegate to MapSession and its session id generation) and there's no capability of custom id generation ATM. We've got an open issue to add support for this (see #11 and #204) so please vote if you'd like to see this.

@vpavic
Copy link
Contributor

vpavic commented Sep 3, 2018

Closing as answered. If you have additional questions or feel that your original question isn't properly answered, please re-open the issue.

@vpavic vpavic closed this as completed Sep 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: stack-overflow A question that's better suited to stackoverflow.com
Projects
None yet
Development

No branches or pull requests

2 participants