mirror of
https://github.com/Noratrieb/karlauth.git
synced 2026-01-14 14:25:02 +01:00
oops
This commit is contained in:
parent
dfc6771135
commit
e8419c3a14
7 changed files with 205 additions and 205 deletions
|
|
@ -1,2 +1,2 @@
|
||||||
# nein
|
# nein
|
||||||
zu windows
|
zu windows
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
-- This file should undo anything in `up.sql`
|
-- This file should undo anything in `up.sql`
|
||||||
|
|
||||||
DROP TABLE users;
|
DROP TABLE users;
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
-- Your SQL goes here
|
-- Your SQL goes here
|
||||||
|
|
||||||
CREATE TABLE users
|
CREATE TABLE users
|
||||||
(
|
(
|
||||||
id SERIAL NOT NULL PRIMARY KEY,
|
id SERIAL NOT NULL PRIMARY KEY,
|
||||||
first_name TEXT NOT NULL,
|
first_name TEXT NOT NULL,
|
||||||
last_name TEXT NOT NULL,
|
last_name TEXT NOT NULL,
|
||||||
email TEXT NOT NULL,
|
email TEXT NOT NULL,
|
||||||
created_at TIMESTAMP NOT NULL
|
created_at TIMESTAMP NOT NULL
|
||||||
);
|
);
|
||||||
|
|
@ -1,39 +1,39 @@
|
||||||
use super::models::{NewUser, User};
|
use super::models::{NewUser, User};
|
||||||
use crate::diesel::QueryDsl;
|
use crate::diesel::QueryDsl;
|
||||||
use crate::diesel::RunQueryDsl;
|
use crate::diesel::RunQueryDsl;
|
||||||
|
|
||||||
use crate::handlers::InputUser;
|
use crate::handlers::InputUser;
|
||||||
use crate::Pool;
|
use crate::Pool;
|
||||||
use diesel::{delete, insert_into};
|
use diesel::{delete, insert_into};
|
||||||
|
|
||||||
type DbResult<T> = Result<T, diesel::result::Error>;
|
type DbResult<T> = Result<T, diesel::result::Error>;
|
||||||
|
|
||||||
pub fn get_all_users(db: &Pool) -> DbResult<Vec<User>> {
|
pub fn get_all_users(db: &Pool) -> DbResult<Vec<User>> {
|
||||||
use super::schema::users::dsl::*;
|
use super::schema::users::dsl::*;
|
||||||
let conn = db.get().unwrap();
|
let conn = db.get().unwrap();
|
||||||
users.load::<User>(&conn)
|
users.load::<User>(&conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_user_by_id(db: &Pool, user_id: i32) -> DbResult<User> {
|
pub fn get_user_by_id(db: &Pool, user_id: i32) -> DbResult<User> {
|
||||||
use super::schema::users::dsl::*;
|
use super::schema::users::dsl::*;
|
||||||
let conn = db.get().unwrap();
|
let conn = db.get().unwrap();
|
||||||
users.find(user_id).get_result::<User>(&conn)
|
users.find(user_id).get_result::<User>(&conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_user(db: &Pool, user: InputUser) -> DbResult<User> {
|
pub fn add_user(db: &Pool, user: InputUser) -> DbResult<User> {
|
||||||
use super::schema::users::dsl::*;
|
use super::schema::users::dsl::*;
|
||||||
let conn = db.get().unwrap();
|
let conn = db.get().unwrap();
|
||||||
let new_user = NewUser {
|
let new_user = NewUser {
|
||||||
first_name: &user.first_name,
|
first_name: &user.first_name,
|
||||||
last_name: &user.last_name,
|
last_name: &user.last_name,
|
||||||
email: &user.email,
|
email: &user.email,
|
||||||
created_at: chrono::Local::now().naive_local(),
|
created_at: chrono::Local::now().naive_local(),
|
||||||
};
|
};
|
||||||
insert_into(users).values(&new_user).get_result(&conn)
|
insert_into(users).values(&new_user).get_result(&conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_user(db: &Pool, user_id: i32) -> DbResult<usize> {
|
pub fn delete_user(db: &Pool, user_id: i32) -> DbResult<usize> {
|
||||||
use super::schema::users::dsl::*;
|
use super::schema::users::dsl::*;
|
||||||
let conn = db.get().unwrap();
|
let conn = db.get().unwrap();
|
||||||
delete(users.find(user_id)).execute(&conn)
|
delete(users.find(user_id)).execute(&conn)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
172
src/auth.rs
172
src/auth.rs
|
|
@ -1,86 +1,86 @@
|
||||||
use crate::errors::ServiceError;
|
use crate::errors::ServiceError;
|
||||||
use crate::models::User;
|
use crate::models::User;
|
||||||
use actix_web::dev::{Payload, ServiceRequest};
|
use actix_web::dev::{Payload, ServiceRequest};
|
||||||
use actix_web::error::ErrorUnauthorized;
|
use actix_web::error::ErrorUnauthorized;
|
||||||
use actix_web::http::header::Header;
|
use actix_web::http::header::Header;
|
||||||
use actix_web::{FromRequest, HttpMessage, HttpRequest};
|
use actix_web::{FromRequest, HttpMessage, HttpRequest};
|
||||||
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||||
use actix_web_httpauth::headers::authorization;
|
use actix_web_httpauth::headers::authorization;
|
||||||
use actix_web_httpauth::headers::authorization::Bearer;
|
use actix_web_httpauth::headers::authorization::Bearer;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Validation};
|
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Validation};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::future;
|
use std::future;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Role {
|
pub enum Role {
|
||||||
None = 0,
|
None = 0,
|
||||||
ReadAll = 1,
|
ReadAll = 1,
|
||||||
WriteAll = 2,
|
WriteAll = 2,
|
||||||
Admin = 3,
|
Admin = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Claims {
|
pub struct Claims {
|
||||||
pub exp: usize,
|
pub exp: usize,
|
||||||
pub uid: i32,
|
pub uid: i32,
|
||||||
pub role: Role,
|
pub role: Role,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromRequest for Claims {
|
impl FromRequest for Claims {
|
||||||
type Error = actix_web::Error;
|
type Error = actix_web::Error;
|
||||||
type Future = std::future::Ready<Result<Self, Self::Error>>;
|
type Future = std::future::Ready<Result<Self, Self::Error>>;
|
||||||
type Config = ();
|
type Config = ();
|
||||||
|
|
||||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||||
future::ready(match authorization::Authorization::<Bearer>::parse(req) {
|
future::ready(match authorization::Authorization::<Bearer>::parse(req) {
|
||||||
Ok(auth) => validate_token(auth.into_scheme().token()),
|
Ok(auth) => validate_token(auth.into_scheme().token()),
|
||||||
Err(_) => Err(ErrorUnauthorized("No Bearer token present")),
|
Err(_) => Err(ErrorUnauthorized("No Bearer token present")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_token(token: &str) -> Result<Claims, actix_web::Error> {
|
fn validate_token(token: &str) -> Result<Claims, actix_web::Error> {
|
||||||
let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET env var");
|
let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET env var");
|
||||||
|
|
||||||
let decoded = jsonwebtoken::decode::<Claims>(
|
let decoded = jsonwebtoken::decode::<Claims>(
|
||||||
&token,
|
&token,
|
||||||
&DecodingKey::from_secret(secret.as_bytes()),
|
&DecodingKey::from_secret(secret.as_bytes()),
|
||||||
&Validation::new(Algorithm::HS512),
|
&Validation::new(Algorithm::HS512),
|
||||||
)
|
)
|
||||||
.map_err(|_| ServiceError::JWTokenError)?
|
.map_err(|_| ServiceError::JWTokenError)?
|
||||||
.claims;
|
.claims;
|
||||||
|
|
||||||
if decoded.exp < Utc::now().timestamp() as usize {
|
if decoded.exp < Utc::now().timestamp() as usize {
|
||||||
Err(ServiceError::TokenExpiredError.into())
|
Err(ServiceError::TokenExpiredError.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(decoded)
|
Ok(decoded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_jwt(user: &User) -> Result<String, ServiceError> {
|
pub fn create_jwt(user: &User) -> Result<String, ServiceError> {
|
||||||
create_jwt_role(user, Role::ReadAll)
|
create_jwt_role(user, Role::ReadAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_jwt_role(user: &User, role: Role) -> Result<String, ServiceError> {
|
pub fn create_jwt_role(user: &User, role: Role) -> Result<String, ServiceError> {
|
||||||
let expiration = Utc::now()
|
let expiration = Utc::now()
|
||||||
.checked_add_signed(chrono::Duration::weeks(10))
|
.checked_add_signed(chrono::Duration::weeks(10))
|
||||||
.expect("valid timestamp")
|
.expect("valid timestamp")
|
||||||
.timestamp();
|
.timestamp();
|
||||||
|
|
||||||
let claims = Claims {
|
let claims = Claims {
|
||||||
exp: expiration as usize,
|
exp: expiration as usize,
|
||||||
uid: user.id,
|
uid: user.id,
|
||||||
role,
|
role,
|
||||||
};
|
};
|
||||||
|
|
||||||
let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET env var");
|
let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET env var");
|
||||||
|
|
||||||
let header = jsonwebtoken::Header::new(Algorithm::HS512);
|
let header = jsonwebtoken::Header::new(Algorithm::HS512);
|
||||||
jsonwebtoken::encode(
|
jsonwebtoken::encode(
|
||||||
&header,
|
&header,
|
||||||
&claims,
|
&claims,
|
||||||
&EncodingKey::from_secret(secret.as_bytes()),
|
&EncodingKey::from_secret(secret.as_bytes()),
|
||||||
)
|
)
|
||||||
.map_err(|_| ServiceError::JWTCreationError)
|
.map_err(|_| ServiceError::JWTCreationError)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,41 @@
|
||||||
use actix_web::{error::ResponseError, HttpResponse};
|
use actix_web::{error::ResponseError, HttpResponse};
|
||||||
use derive_more::Display;
|
use derive_more::Display;
|
||||||
|
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
pub enum ServiceError {
|
pub enum ServiceError {
|
||||||
#[display(fmt = "Internal Server Error")]
|
#[display(fmt = "Internal Server Error")]
|
||||||
InternalServerError,
|
InternalServerError,
|
||||||
|
|
||||||
#[display(fmt = "BadRequest: {}", _0)]
|
#[display(fmt = "BadRequest: {}", _0)]
|
||||||
BadRequest(String),
|
BadRequest(String),
|
||||||
|
|
||||||
#[display(fmt = "JWT Creation Error")]
|
#[display(fmt = "JWT Creation Error")]
|
||||||
JWTCreationError,
|
JWTCreationError,
|
||||||
|
|
||||||
#[display(fmt = "JWT Error")]
|
#[display(fmt = "JWT Error")]
|
||||||
JWTokenError,
|
JWTokenError,
|
||||||
|
|
||||||
#[display(fmt = "No Permission Error")]
|
#[display(fmt = "No Permission Error")]
|
||||||
NoPermissionError,
|
NoPermissionError,
|
||||||
|
|
||||||
#[display(fmt = "Token Expired Error")]
|
#[display(fmt = "Token Expired Error")]
|
||||||
TokenExpiredError,
|
TokenExpiredError,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl ResponseError trait allows to convert our errors into http responses with appropriate data
|
// impl ResponseError trait allows to convert our errors into http responses with appropriate data
|
||||||
impl ResponseError for ServiceError {
|
impl ResponseError for ServiceError {
|
||||||
fn error_response(&self) -> HttpResponse {
|
fn error_response(&self) -> HttpResponse {
|
||||||
match self {
|
match self {
|
||||||
ServiceError::InternalServerError => {
|
ServiceError::InternalServerError => {
|
||||||
HttpResponse::InternalServerError().json("Internal Server Error, Please try later")
|
HttpResponse::InternalServerError().json("Internal Server Error, Please try later")
|
||||||
}
|
}
|
||||||
ServiceError::BadRequest(ref message) => HttpResponse::BadRequest().json(message),
|
ServiceError::BadRequest(ref message) => HttpResponse::BadRequest().json(message),
|
||||||
ServiceError::JWTCreationError => {
|
ServiceError::JWTCreationError => {
|
||||||
HttpResponse::InternalServerError().json("Could not fetch JWKS")
|
HttpResponse::InternalServerError().json("Could not fetch JWKS")
|
||||||
}
|
}
|
||||||
ServiceError::JWTokenError => HttpResponse::BadRequest().json("Invalid JWT"),
|
ServiceError::JWTokenError => HttpResponse::BadRequest().json("Invalid JWT"),
|
||||||
ServiceError::NoPermissionError => HttpResponse::Unauthorized().json("No permissions"),
|
ServiceError::NoPermissionError => HttpResponse::Unauthorized().json("No permissions"),
|
||||||
ServiceError::TokenExpiredError => HttpResponse::Unauthorized().json("Token expired"),
|
ServiceError::TokenExpiredError => HttpResponse::Unauthorized().json("Token expired"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,27 @@
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Queryable)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Queryable)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub first_name: String,
|
pub first_name: String,
|
||||||
pub last_name: String,
|
pub last_name: String,
|
||||||
pub email: String,
|
pub email: String,
|
||||||
pub created_at: chrono::NaiveDateTime,
|
pub created_at: chrono::NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable, Debug)]
|
#[derive(Insertable, Debug)]
|
||||||
#[table_name = "users"]
|
#[table_name = "users"]
|
||||||
pub struct NewUser<'a> {
|
pub struct NewUser<'a> {
|
||||||
pub first_name: &'a str,
|
pub first_name: &'a str,
|
||||||
pub last_name: &'a str,
|
pub last_name: &'a str,
|
||||||
pub email: &'a str,
|
pub email: &'a str,
|
||||||
pub created_at: chrono::NaiveDateTime,
|
pub created_at: chrono::NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<User> for HttpResponse {
|
impl From<User> for HttpResponse {
|
||||||
fn from(user: User) -> Self {
|
fn from(user: User) -> Self {
|
||||||
HttpResponse::Ok().json(user)
|
HttpResponse::Ok().json(user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue