feat: implement basic session authentication
This commit is contained in:
parent
df741c931b
commit
902de85131
10 changed files with 204 additions and 97 deletions
|
|
@ -66,7 +66,7 @@ pub fn run_migrations(pool: &DbPool, migrations: &[&str]) -> rusqlite::Result<()
|
|||
while next_version < migrations.len() {
|
||||
let tx = conn.transaction()?;
|
||||
|
||||
tx.execute(migrations[next_version], ())?;
|
||||
tx.execute_batch(migrations[next_version])?;
|
||||
|
||||
let cur_time = chrono::Local::now().timestamp();
|
||||
tx.execute(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,21 @@
|
|||
use argon2::password_hash::rand_core::{OsRng, RngCore};
|
||||
use rusqlite::Row;
|
||||
|
||||
use super::{DbError, DbPool, User};
|
||||
|
||||
pub struct Session {
|
||||
id: u64,
|
||||
user_id: i32,
|
||||
pub id: u64,
|
||||
pub user_id: i32,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn from_row(row: &Row<'_>) -> Result<Self, rusqlite::Error> {
|
||||
Ok(Self {
|
||||
id: row.get("id")?,
|
||||
user_id: row.get("user_id")?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn user_from_id(pool: &DbPool, id: u64) -> Result<Option<super::User>, DbError> {
|
||||
let conn = pool.get()?;
|
||||
|
||||
|
|
@ -16,4 +26,14 @@ impl Session {
|
|||
Err(err) => Err(DbError::Db(err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_for_user(pool: &DbPool, user_id: i32) -> Result<Self, DbError> {
|
||||
let id: u64 = OsRng.next_u64();
|
||||
|
||||
let conn = pool.get()?;
|
||||
let mut stmt =
|
||||
conn.prepare("insert into sessions (id, user_id) values ($1, $2) returning *")?;
|
||||
|
||||
Ok(stmt.query_row((&id, &user_id), Self::from_row)?)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, SaltString},
|
||||
Argon2, PasswordHash, PasswordHasher, PasswordVerifier,
|
||||
};
|
||||
use rusqlite::Row;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -5,17 +9,17 @@ use super::{DbError, DbPool};
|
|||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct User {
|
||||
id: i32,
|
||||
username: String,
|
||||
password_hash: String,
|
||||
admin: bool,
|
||||
pub id: i32,
|
||||
pub username: String,
|
||||
pub password_hash: String,
|
||||
pub admin: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct NewUser {
|
||||
username: String,
|
||||
password: String,
|
||||
admin: bool,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub admin: bool,
|
||||
}
|
||||
|
||||
impl User {
|
||||
|
|
@ -27,19 +31,48 @@ impl User {
|
|||
admin: row.get("admin")?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn by_username(pool: &DbPool, username: impl AsRef<str>) -> Result<Option<Self>, DbError> {
|
||||
let conn = pool.get()?;
|
||||
|
||||
let mut stmt = conn.prepare("select * from users where username = $1")?;
|
||||
|
||||
match stmt.query_row((username.as_ref(),), User::from_row) {
|
||||
Ok(user) => Ok(Some(user)),
|
||||
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
|
||||
Err(err) => Err(DbError::Db(err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_password(&self, password: impl AsRef<str>) -> bool {
|
||||
let password_hash = PasswordHash::new(&self.password_hash).unwrap();
|
||||
|
||||
Argon2::default()
|
||||
.verify_password(password.as_ref().as_bytes(), &password_hash)
|
||||
.is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_password(password: impl AsRef<str>) -> String {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let argon2 = Argon2::default();
|
||||
|
||||
argon2
|
||||
.hash_password(password.as_ref().as_bytes(), &salt)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
impl NewUser {
|
||||
pub fn insert(self, pool: &DbPool) -> Result<User, DbError> {
|
||||
let conn = pool.get()?;
|
||||
|
||||
let password_hash = hash_password(&self.password);
|
||||
|
||||
let mut stmt = conn.prepare(
|
||||
"insert into users (username, password_hash, admin) values ($1, $2, $3) returning *",
|
||||
)?;
|
||||
|
||||
Ok(stmt.query_row(
|
||||
(&self.username, &self.password, &self.admin),
|
||||
User::from_row,
|
||||
)?)
|
||||
Ok(stmt.query_row((&self.username, password_hash, &self.admin), User::from_row)?)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue