Skip to content

Commit a7ee889

Browse files
committed
feat: implement User
1 parent 8d68876 commit a7ee889

File tree

6 files changed

+131
-6
lines changed

6 files changed

+131
-6
lines changed

src/server/auth/context.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//! Contains the [`auth`](super) [`Context`] which is used by the [server](crate::server).
2+
3+
use axum_login::{extractors::AuthContext, SqlxStore};
4+
use sqlx::Pool;
5+
6+
use super::User;
7+
8+
/// The [`AuthContext`] used by the [`winvoice_server::server`].
9+
pub type Context<Db> = AuthContext<String, User, SqlxStore<Pool<Db>, User, String>, String>;

src/server/auth/init_users_table.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,21 @@ impl InitUsersTable for sqlx::Postgres
2020
where
2121
C: Executor<'conn, Database = Self>,
2222
{
23+
sqlx::query!(
24+
"CREATE TABLE IF NOT EXISTS users
25+
(
26+
employee_id bigint REFERENCES employees(id),
27+
id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
28+
role text DEFAULT 'guest',
29+
password text NOT NULL,
30+
username text NOT NULL,
31+
32+
CONSTRAINT users__username_uq UNIQUE (username)
33+
);"
34+
)
35+
.execute(connection)
36+
.await?;
37+
2338
Ok(())
2439
}
2540
}

src/server/auth/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! Contains data and algorithms used for authenticating users.
22
3+
mod context;
34
mod init_users_table;
45
mod user;
56

7+
pub use context::Context;
68
pub use init_users_table::InitUsersTable;
9+
pub use user::User;

src/server/auth/user.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,73 @@
11
//! Contains the definition for what a [`User`] row in the [`Database`](sqlx::Database) is.
2+
3+
#![allow(clippy::std_instead_of_core)]
4+
5+
mod auth_user;
6+
7+
use sqlx::FromRow;
8+
use winvoice_schema::Id;
9+
10+
/// Corresponds to the `users` table in the [`winvoice-server`](crate) database.
11+
#[derive(Clone, Debug, Default, Eq, FromRow, Hash, Ord, PartialEq, PartialOrd)]
12+
pub struct User
13+
{
14+
/// The [`User`]'s [`Employee`](winvoice_schema::Employee) [`Id`], if they are employed.
15+
employee_id: Option<Id>,
16+
17+
/// The [`Id`] of the [`User`].
18+
id: Id,
19+
20+
/// The role of the [`User`]. Controls permissions.
21+
role: String,
22+
23+
/// Get the [`User`]'s [`argon2`]-hashed password.
24+
password: String,
25+
26+
/// Get the [`User`]'s username.
27+
username: String,
28+
}
29+
30+
impl User
31+
{
32+
/// Create a new [`User`].
33+
pub const fn new(
34+
employee_id: Option<Id>,
35+
id: Id,
36+
role: String,
37+
password: String,
38+
username: String,
39+
) -> Self
40+
{
41+
Self { employee_id, id, role, password, username }
42+
}
43+
44+
/// The [`User`]'s [`Employee`](winvoice_schema::Employee) [`Id`], if they are employed.
45+
pub const fn employee_id(&self) -> Option<i64>
46+
{
47+
self.employee_id
48+
}
49+
50+
/// The [`Id`] of the [`User`].
51+
pub const fn id(&self) -> i64
52+
{
53+
self.id
54+
}
55+
56+
/// The role of the [`User`]. Controls permissions.
57+
pub fn role(&self) -> &str
58+
{
59+
self.role.as_ref()
60+
}
61+
62+
/// Get the [`User`]'s [`argon2`]-hashed password.
63+
pub fn password(&self) -> &str
64+
{
65+
self.password.as_ref()
66+
}
67+
68+
/// Get the [`User`]'s username.
69+
pub fn username(&self) -> &str
70+
{
71+
self.username.as_ref()
72+
}
73+
}

src/server/auth/user/auth_user.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//! Contains an implementation of [`AuthUser`] for [`User`].
2+
3+
use axum_login::{secrecy::SecretVec, AuthUser};
4+
5+
use super::User;
6+
7+
impl AuthUser<String, String> for User
8+
{
9+
fn get_id(&self) -> String
10+
{
11+
self.username.clone()
12+
}
13+
14+
fn get_password_hash(&self) -> SecretVec<u8>
15+
{
16+
SecretVec::new(Vec::from(self.password()))
17+
}
18+
19+
fn get_role(&self) -> Option<String>
20+
{
21+
Some(self.role.clone())
22+
}
23+
}

src/server/state.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
33
mod clone;
44

5-
use casbin::{CoreApi, EnforceArgs, Enforcer};
5+
use casbin::{CoreApi, Enforcer};
66
use sqlx::{Database, Pool};
77

8+
use super::auth::User;
89
use crate::{
910
lock::Lock,
1011
permissions::{Action, Object},
@@ -33,16 +34,18 @@ where
3334
}
3435

3536
/// Check whether `subject` has permission to `action` on `object`.
36-
pub async fn has_permission<TSubject>(
37+
pub async fn has_permission(
3738
&self,
38-
subject: TSubject,
39+
user: User,
3940
object: Object,
4041
action: Action,
4142
) -> casbin::Result<bool>
42-
where
43-
(TSubject, Object, Action): EnforceArgs,
4443
{
45-
self.permissions.read().await.enforce((subject, object, action))
44+
let permissions = self.permissions.read().await;
45+
let has_permission = permissions.enforce((user.username(), object, action))? ||
46+
permissions.enforce((user.role(), object, action))?;
47+
48+
Ok(has_permission)
4649
}
4750

4851
/// Get the [`Pool`] of connections to the [`Database`].

0 commit comments

Comments
 (0)