crypto and crate feature mailer and crate feature serde and non-WebAssembly only.Expand description
Sign-up, login, logout, password reset and email confirmation (18.35.0,
#92): the account pages and API every app needs, as one middleware.
Features crypto, mailer and serde (all in the web preset).
use std::sync::Arc;
use rust_web_server::app::App;
use rust_web_server::auth_flows::{AuthFlows, CurrentUser, MemoryUserStore};
use rust_web_server::extract::FromRequest;
use rust_web_server::mailer::TestMailbox;
use rust_web_server::response::{Response, STATUS_CODE_REASON_PHRASE};
let auth = AuthFlows::new(b"a secret of at least 32 bytes, from config!", "https://example.com", MemoryUserStore::new(), TestMailbox::new());
let app = App::with_state(())
.group("/account", |g| {
g.guard(rust_web_server::auth_flows::signed_in)
.get("/", |request, _, _, _| {
let user = CurrentUser::from_request(request).unwrap();
Response::text(STATUS_CODE_REASON_PHRASE.n200_ok, &user.email)
})
})
.wrap(auth);| Request | JSON (Content-Type: application/json) | Form (HTML) |
|---|---|---|
POST /auth/signup {email, password} | 201 {user} and signed in (or confirmation_required) | redirect + flash |
POST /auth/login {email, password} | 200 {user}, 401, 403 unconfirmed | redirect to return_to or the after-login path |
POST /auth/logout | 204 | redirect |
GET /auth/me | 200 {user} or 401 | — |
POST /auth/password/forgot {email} | 202, whether or not the account exists | redirect + flash |
POST /auth/password/reset {token, password} | 200 {user} and signed in, 400 bad link | redirect + flash |
GET /auth/confirm?token= / POST /auth/confirm {token} | 200 {user}, 400 | redirect + flash |
POST /auth/confirm/resend {email} | 202 | redirect + flash |
GET /auth/login, /auth/signup, /auth/password/forgot, /auth/password/reset?token= | — | the forms |
Sessions are a signed cookie (rws_auth, HttpOnly, SameSite=Lax,
Secure when the base URL is https) holding the user id, an expiry
and a fingerprint of the password hash — no session store, any replica
can check it, and changing the password signs every session out.
Links in the emails carry signed tokens the same way: a reset link
stops working once the password changes, and expires after an hour; a
confirmation link after three days. Logins, sign-ups and the email
requests are rate limited per client IP (10 a minute by default): the
address a proxy in trusted_proxies (private ranges by default)
forwarded, else the peer’s.
For every other request the middleware checks the session cookie and
passes the account to the app as CurrentUser (a handler argument);
signed_in is a route guard. Headers a client sends in its place are
removed.
Structs§
- Auth
Flows - The auth flows. A middleware:
app.wrap(auth), after (inside)FlashLayerandCsrfLayer, which must see the pages it draws. See the module docs. - Auth
User - An account as the auth flows see it.
- Current
User - The signed-in account, as
AuthFlowspassed it on: a handler argument that answers401without a session. - DbUser
Store model-mysqlormodel-postgresormodel-sqlite - Accounts in the
rws_userstable of aDbPool(model-*features), created if absent: - Memory
User Store - Accounts in memory: tests and trying things out. Clones share them.
Traits§
- User
Store - Accounts: implement it over your users table, or use
MemoryUserStore/DbUserStore. Errors are messages; the flows answer them500. The methods are synchronous: the flows run as a middleware, on the blocking pool.
Functions§
- signed_
in - A route guard:
401without a session (group(…).guard(signed_in)). - signed_
in_ or_ redirect - A route guard for pages: without a session, a redirect to
login(withreturn_toset to the page asked for).