Giter Club home page Giter Club logo

Comments (11)

edjiang avatar edjiang commented on May 21, 2024

Hey @gabriellanata, thanks for the PR! I'd love to learn more about why you're trying to extend Subject. Subject isn't injectable in Turnstile, and I think right now it's guaranteed that the Subject API will allow you to be relatively secure =]

If there's a good reason we can open it up. Otherwise, it might be a good idea to put a "facade" on top of the Subject API for whatever integration you're making.

Happy to talk more! You can join our slack channel here: https://talkstormpath.shipit.xyz

from turnstile.

gabriellanata avatar gabriellanata commented on May 21, 2024

Oh I see, I had assumed that we were supposed to have our User object subclass Subject to gain the methods automatically. Now I understand that we are supposed to have our User object be facade that interacts with Subject behind it. Sorry for the confusion, I think this is not very clear in the documentation, maybe it should be updated to reflect that. Thanks!

from turnstile.

edjiang avatar edjiang commented on May 21, 2024

No problem. I'll keep this issue open until I update the docs. Unfortunately they're not the most comprehensive for integrators, but at this time the number is low =]

Just curious, what are you integrating Turnstile with?

from turnstile.

edjiang avatar edjiang commented on May 21, 2024

As an example, I would recommend checking out the Perfect integration as an example of a lightweight integration. It's only ~200 LOC.

For the Perfect integration, it's using the Subject API without a facade, and I think works pretty well.

https://github.com/stormpath/Turnstile-Perfect

If you want to see how Vapor integrated it, check out: https://github.com/vapor/vapor/tree/master/Sources/Auth/Authentication

It's a little of a bigger integration, but you can see how they made request.auth a facade for the Subject, as well as wrapping the Realm and SessionManager. They did a great job there as well =]

from turnstile.

gabriellanata avatar gabriellanata commented on May 21, 2024

Thanks!, it all makes more sense now.

Honestly at the moment I have not been able to decide which Swift web framework to work with, all three of the main ones (Perfect, Vapor, Kitura) have strong points. Currently i'm working with vapor just because it has the simplest api but I might decide to change later.

For that reason I'm trying to integrate most things myself and just use the web framework as the face of the server. I know this might prevent me from taking full advantage of all the power in each of the frameworks, but it reduces the amount of refactoring I have to do if I decide to switch later when the platform matures and a leader emerges.

from turnstile.

edjiang avatar edjiang commented on May 21, 2024

Cool -- makes sense.

In that case, Vapor does allow you to pass in your own Turnstile instance, or pass in your own Realm.

https://github.com/vapor/vapor/blob/master/Sources/Auth/Authentication/AuthMiddleware.swift#L33

If you want to interact directly with the Subject without the Vapor facade, it's stored in request.storage["subject"], so you could add a extension like this:

extension Request {
    var subject: Subject {
        return request.storage["subject"] as! Subject
    }
}

from turnstile.

edjiang avatar edjiang commented on May 21, 2024

Just to let you know, I've personally met members of all teams and they're all dedicated to making server-side Swift a thing, and have decent funding =] So I wouldn't expect Vapor, Kitura, or Perfect to go away in the near-mid future -- but of course the communities around them may change.

from turnstile.

nawar avatar nawar commented on May 21, 2024

Just jumping into this conversations, I've also hit this when trying to work with the Perfect's example which integrates with Turnstile. My use case is, I want to return the uniqueID when registering the user in order to use that as a foreign key in another table.

from turnstile.

edjiang avatar edjiang commented on May 21, 2024

Hey @nawar, you should be able to access the uniqueID by calling subject.authDetails?.account?.uniqueID. What would you want to do by subclassing Subject?

from turnstile.

nawar avatar nawar commented on May 21, 2024

@edjiang I tried that already. In Perfect's Realm implementation, they are trying to return the Account in their register() and authenticate() functions as you can see below

public func authenticate(credentials: AccessToken) throws -> Account {
        let account = AuthAccount()
        let token = AccessTokenStore()
        do {
                try token.get(credentials.string)
                if token.check() == false {
                        throw IncorrectCredentialsError()
                }
                try account.get(token.userid)
                return account
        } catch {
                throw IncorrectCredentialsError()
        }
}
// ...
public func register(credentials: Credentials) throws -> Account {

        let account = AuthAccount()
        let newAccount = AuthAccount()
        newAccount.id(String(random.secureToken))

        switch credentials {
        case let credentials as UsernamePassword:
                do {
                        if account.exists(credentials.username) {
                                throw AccountTakenError()
                        }
                        newAccount.username = credentials.username
                        newAccount.password = credentials.password
                        do {
                                try newAccount.make() // can't use save as the id is populated
                        } catch {
                                print("REGISTER ERROR: \(error)")
                        }
                } catch {
                        throw AccountTakenError()
                }
        default:
                throw UnsupportedCredentialsError()
        }
        return newAccount
}

And in your implementation of Subject, you are maintaining Account in the login() function by adding it to authDetails and discarding it in register().

 public func login(credentials: Credentials, persist: Bool = false) throws {
        let account = try turnstile.realm.authenticate(credentials: credentials)
        let sessionID: String? = persist ? turnstile.sessionManager.createSession(account: account) : nil
        let credentialType = type(of: credentials)
        
        authDetails = AuthenticationDetails(account: account, sessionID: sessionID, credentialType: credentialType)
    }
    
    /// Another one bites the dust.. 
    public func register(credentials: Credentials) throws {
        _ = try turnstile.realm.register(credentials: credentials)
    }

Following with your suggestion, this only worked with the login() function. I even cast Auth to AuthAccount and get access to the other properties of AuthAccount

if let authAccount = request.user.authDetails?.account as? AuthAccount {
// ...
}

So I think, the better suggestion is to let register() assigns the authDetails instance as well.

from turnstile.

edjiang avatar edjiang commented on May 21, 2024

Gotcha. If you want the user to be logged in after registration, I would call register and login in quick succession. That would set the "authDetails".

For instance: https://github.com/stormpath/Turnstile-Perfect-Example/blob/master/Sources/main.swift#L74

The Subject API is meant to be a guide to the current authentication state of your application. Not all applications will have registration + login in one step, especially if there's a verification process. Thus, setting the authDetails is not a good idea.

Just in general, from the docs:

The Subject API in Turnstile also supports registration, however this is a convenience for basic use cases. Since different apps have different rules on registration and user managment, it's expected that you will most likely write your own registration and user management logic.

I'm unfamiliar with how the Perfect implementation you're using works, but I'm guessing you can call register directly on the Realm if you want to get the full account information.

Hope this helps!

from turnstile.

Related Issues (19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.