这是indexloc提供的服务,不要输入任何密码
Skip to content

Pass session to cookie session factory allowing to modify cookie based on session data #3278

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

Open
wants to merge 2 commits into
base: vapor-5
Choose a base branch
from

Conversation

rafalwojcik
Copy link

@rafalwojcik rafalwojcik commented Jan 5, 2025

Motivation

I was struggling to implement a “Remember me” feature for user login. Even after adding middleware like the snippet below, the SessionMiddleware kept overriding my cookie values.

struct ExtendSessionMiddleware<A: Authenticatable>: AsyncMiddleware {
    let authenticableType: A.Type

    init(authenticableType: A.Type) {
        self.authenticableType = authenticableType
    }

    func respond(to req: Request, chainingTo next: AsyncResponder) async throws -> Response {
        guard
            req.auth.has(authenticableType),
            let rememberMe = Bool(req.session.data["remeberMe"] ?? "")
        else { return try await next.respond(to: req) }

        let response = try await next.respond(to: req)

        let extendTime: TimeInterval = rememberMe ? 7 * 24 * 60 * 60 : 24 * 60 * 60
        let expiresAt = Date().addingTimeInterval(extendTime)

        let cookieName = req.application.sessions.configuration.cookieName
        if var cookie = req.cookies[cookieName] {
            cookie.expires = expiresAt
            cookie.maxAge = Int(extendTime)
            response.cookies[cookieName] = cookie
        }

        return response
    }
}

Idea

My proposed solution is to pass the session itself to the cookie factory. This approach allows reading session values set during user login and overriding the default session behavior.

Usage

var config = SessionsConfiguration.default()
config.cookieFactory = { sessionID, session in
    let rememberMe = Bool(session.data["remeberMe"] ?? "")
    let time: TimeInterval = (rememberMe ?? false) ? 7 * 24 * 60 * 60 : 24 * 60 * 60
    let expiresAt = Date().addingTimeInterval(time)
    return .init(string: sessionID.string, expires: expiresAt)
}
application.middleware.use(SessionsMiddleware(session: application.sessions.driver, configuration: config))

With this code, the session expires after one day if the user doesn’t select “Remember me,” and after seven days if they do.

Question

Is there another way to solve this issue without requiring any changes from my PR?

@rafalwojcik
Copy link
Author

I'm writing tests now for this functionality

@0xTim
Copy link
Member

0xTim commented Jan 5, 2025

This is a no go at the moment as it changes the public API. Here's an example of doing it via middleware https://github.com/brokenhandsio/SteamPress/blob/vapor4/Sources/SteamPress/Middleware/BlogRememberMeMiddleware.swift

@rafalwojcik
Copy link
Author

@0xTim, unfortunately, the above solution doesn't work with Vapor 4. I can understand that breaking public API won't go to the Vapor 4 release. Could you consider including it in Vapor 5?

@rafalwojcik rafalwojcik changed the base branch from main to vapor-5 January 5, 2025 20:46
@rafalwojcik rafalwojcik force-pushed the rafalwojcik/session-cookie-config branch from 2b3228f to f9178da Compare January 5, 2025 20:50
@rafalwojcik
Copy link
Author

@0xTim I've rebased changes over vapor-5 branch and updated PR base

@0xTim
Copy link
Member

0xTim commented Jan 5, 2025

We can definitely look at improving the usability and API for Vapor 5. But that solution should work fine for Vapor 4 since I built it for that

@rafalwojcik
Copy link
Author

Hmm, I've tried almost all things, and SessionsMiddleware is always called at the end of the middleware chain, so it overrides cookie value.

@0xTim
Copy link
Member

0xTim commented Jan 5, 2025

Register the remember me middleware before the sessions middleware and it should work

@rafalwojcik
Copy link
Author

When I registered it, before I couldn't access session because it not initalized and fatalError is triggered.

@0xTim
Copy link
Member

0xTim commented Jan 21, 2025

@rafalwojcik can you show the code? Because the session should be initialised on the way in and then read by the remember me middleware on the way out

@0xTim 0xTim force-pushed the vapor-5 branch 2 times, most recently from 7a05c39 to 374a162 Compare February 8, 2025 03:37
@rafalwojcik rafalwojcik force-pushed the rafalwojcik/session-cookie-config branch from f9178da to ea7e34a Compare June 6, 2025 22:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants