bocadilloproject / bocadillo

(UNMAINTAINED) Fast, scalable and real-time capable web APIs for everyone
https://bocadilloproject.github.io
MIT License
396 stars 41 forks source link

User accounts #100

Closed florimondmanca closed 5 years ago

florimondmanca commented 5 years ago

Is your feature request related to a problem? Please describe. Users and authentication is an extremely common problem. Many web apps include some form of account system, user credentials, and the like. We don't want to let our users reinvent the wheel every time. Users information security is at stake.

Describe the solution you'd like

Permissions will be tackled later (or perhaps at the same time, since Starlette offers some of that).

Describe alternatives you've considered Build on Starlette's authentication helpers (docs, code). This will need to build upon an ORM. So, should we make Tortoise our officially supported ORM?

Additional context This is very much a WIP draft, open to discussion.

Marlysson commented 5 years ago

Hi @florimondmanca there are something are doing in this issue?

I'm looking for contribute here with some ideas..

Is the types of authentication that you plan implement is just database ( using model data ) or do you planning use cookie, jwt session.. or whatever..

florimondmanca commented 5 years ago

Hi @Marlysson :-)

Supporting cookie-based auth, JWT etc would be interesting but I think the first step towards that is to build a simple, strong and secure user model.

In fact, in terms of roadmap I'm thinking of (and maybe this won't be that linear):

  1. Build the User model (and see if we're heading to the right direction).
  2. Introduce an "authentication backend framework" that defines how clients should be authenticated. (This is where Starlette's helpers would come in handy I think.) This would be useful so we can support basic auth first and later expand to have more backends, such as token-based, JWT, session, etc, as you mentioned.
  3. My intuition says we'll also need helpers to abstract away which backend we're using. Also include helpers that abstract away which backend we're using.
  4. Build the "basic" auth backend to authenticate using username/password.

As for 1), there are more requirements to the User model which I'll add to the issue description:

In any case, I think we need to define properly what needs to be done before starting work on this. Do you see anything else?

Marlysson commented 5 years ago

Wow, sounds very good this approach!!

1.Will we build all on top from Starlette ?

  1. About the ORM, will we use the Tortoise ?

Do you have some design decision already do? As abstract classes' name that will be an "interfaces" between various backends that will be supported..

Example:

class BackendAuthenticator:
class Authenticator:
class AuthBackend:
florimondmanca commented 5 years ago

1.Will we build all on top from Starlette ?

That's my first bet, but I haven't made any attempt yet and only looked at the docs. We'd need to take a closer look at how to use the primitives Starlette provides.

  1. About the ORM, will we use the Tortoise ?

Yes, let's go for that. 😊 But let's make sure that the basic user interface / model doesn't integrate with any data layer, and only serves as a means to store information. That way we're less tightly coupled to Tortoise.

Do you have some design decision already do? As abstract classes' name that will be an "interfaces" between various backends that will be supported..

I suggest you take a look at Starlette's Authentication docs, and perhaps dig into the source code here and there. The docs page also shows an example of an BasicAuthBackend for Basic access authentication.

Starlette auth has an interesting separation between users, which contain the user's identity, and credentials which store the scopes (aka privileges, aka permissions) granted to that user. For example, admin is just another scope, which I think is quite elegant and avoids polluting the user model with authorization stuff.

As for terminology, they use the terms User (and also provide a BaseUser interface), AuthCredentials and AuthenticationBackend.

Checking credentials provided in the request is implemented using an AuthenticationMiddleware. They also have some utilities such as @requires. However, I don't think these will work out of the box because I bet they integrate with Starlette's views/routing system which is different Bocadillo's. We'll probably need to adjust some things there. These adjustments are what make this feature non-trivial IMO.

florimondmanca commented 5 years ago

I've opened an initial PR for this in #270.

The last time we discussed this, we thought about integrating with Tortoise ORM directly. I think that's a bad idea — instead, we should build a generic auth "platform" upon which we can build specific libraries.

For example, if #270 is merged in, we could implement token-based authentication by creating a TokenAuth authentication backend, provide an ObtainAuthToken view, and release that as bocadillo-auth-token.

A similar thing could be done for basic auth as bocadillo-auth-basic, etc.

As for the user model, we could have an officially supported one based on typesystem and orm (with password hashing, etc) as bocadillo-user (not even sure it would need to be tied to Bocadillo!).

Besides, #270 provides a generic ModelBackend which we could build a subclass for and release that as bocadillo-auth-model (reusing bocadillo-user).

I really like how some ecosystems like Vue's have a solid core and then officially supported extensions on top of that: people can just use the officially supported ones, or build on top of the framework core to publish alternatives. It's extensible with defaults.

florimondmanca commented 5 years ago

Update: began working on https://github.com/florimondmanca/starlette-auth-toolkit, hopefully makes it easier for Bocadillo & others to add authentication without the hassle.

richardnpaul commented 5 years ago

Argon2 is quite commonly used now as a good default algorithm in Django circles.

florimondmanca commented 5 years ago

Yes, and Django ships with a bundle of other hashers I believe.

Obviously, implementing password hashers is hard and must be done right. I was thinking about using passlib instead, probably inside starlette-auth-toolkit itself. :+1:

richardnpaul commented 5 years ago

I originally wrote a much longer comment but decided it was probably too much but since commented along those lines I'll write it now anyway.

Yes, in Django you have a list(?) of hashes the first being the preferred option and also, the hash algorithm which will be used to replace other supported types on the next login. This is good to have as it means that if you work with a project long enough algorithms become deprecated and new ones become the standard.

I recently wrote a management command to migrate the data from a Django 1.0 app to 2.0 and the 1.0 app was using SHA1. I just had to include this algorithm at the bottom of the list of hashers with argon2 at the top and the next time that the users log in they will be seemlessly updated to the new hashing algorithm.

florimondmanca commented 5 years ago

I've used Django a lot but I never changed the default hashers (which means I used PBKDF2), so it's good to read an example use case of having a whole list of hashers. It does allow to change the hashing algorithm without having the reset all passwords. So thanks, let's keep this in the back of our minds! Hopefully Passlib allows to do something like this (if you want to investigate, feel free to do so :+1:).