Adds user authorization to the actix backend.
This commit is contained in:
		
							parent
							
								
									1c8110cdb0
								
							
						
					
					
						commit
						534e6867d8
					
				
							
								
								
									
										26
									
								
								backend-actix/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										26
									
								
								backend-actix/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -393,6 +393,7 @@ dependencies = [ | ||||
|  "js-sys", | ||||
|  "num-integer", | ||||
|  "num-traits", | ||||
|  "serde", | ||||
|  "time 0.1.45", | ||||
|  "wasm-bindgen", | ||||
|  "winapi", | ||||
| @ -433,9 +434,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cpufeatures" | ||||
| version = "0.2.5" | ||||
| version = "0.2.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" | ||||
| checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
| ] | ||||
| @ -483,7 +484,7 @@ dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "scratch", | ||||
|  "syn 2.0.9", | ||||
|  "syn 2.0.10", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| @ -500,7 +501,7 @@ checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn 2.0.9", | ||||
|  "syn 2.0.10", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| @ -524,6 +525,7 @@ checksum = "4391a22b19c916e50bec4d6140f29bdda3e3bb187223fe6e3ea0b6e4d1021c04" | ||||
| dependencies = [ | ||||
|  "bitflags", | ||||
|  "byteorder", | ||||
|  "chrono", | ||||
|  "diesel_derives", | ||||
|  "itoa", | ||||
|  "pq-sys", | ||||
| @ -767,9 +769,9 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "indexmap" | ||||
| version = "1.9.2" | ||||
| version = "1.9.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" | ||||
| checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" | ||||
| dependencies = [ | ||||
|  "autocfg", | ||||
|  "hashbrown", | ||||
| @ -1144,9 +1146,9 @@ dependencies = [ | ||||
| 
 | ||||
| [[package]] | ||||
| name = "regex" | ||||
| version = "1.7.2" | ||||
| version = "1.7.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c" | ||||
| checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" | ||||
| dependencies = [ | ||||
|  "aho-corasick", | ||||
|  "memchr", | ||||
| @ -1233,7 +1235,7 @@ checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn 2.0.9", | ||||
|  "syn 2.0.10", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| @ -1341,9 +1343,9 @@ dependencies = [ | ||||
| 
 | ||||
| [[package]] | ||||
| name = "syn" | ||||
| version = "2.0.9" | ||||
| version = "2.0.10" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0da4a3c17e109f700685ec577c0f85efd9b19bcf15c913985f14dc1ac01775aa" | ||||
| checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
| @ -1376,7 +1378,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn 2.0.9", | ||||
|  "syn 2.0.10", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | ||||
| @ -10,9 +10,9 @@ actix-web = "4" | ||||
| serde = { version = "1.0", features = ["derive"] } | ||||
| serde_json = "1.0" | ||||
| uuid = { version = "1.3.0", features = ["serde", "v4"] } | ||||
| diesel = { version = "2.0", features = ["postgres", "r2d2", "uuid"] } | ||||
| diesel = { version = "2.0", features = ["postgres", "r2d2", "uuid", "chrono"] } | ||||
| diesel-derive-enum = { version = "2.0", features = ["postgres"] } | ||||
| argon2 = "0.5" | ||||
| chrono = "0.4" | ||||
| chrono = { version = "0.4", features = ["serde"] } | ||||
| jsonwebtoken = "8.1" | ||||
| validator = { version = "0.16", features = ["derive"] } | ||||
| @ -5,7 +5,7 @@ use actix_web::HttpServer; | ||||
| use actix_web::App; | ||||
| use actix_web::web; | ||||
| use diesel::PgConnection; | ||||
| use request::{login, register}; | ||||
| use request::{login, register, gamenights}; | ||||
| use diesel::r2d2::ConnectionManager; | ||||
| use diesel::r2d2::Pool; | ||||
| 
 | ||||
| @ -28,6 +28,7 @@ async fn main() -> std::io::Result<()> { | ||||
|             .app_data(web::Data::new(pool.clone())) | ||||
|             .service(login) | ||||
|             .service(register) | ||||
|             .service(gamenights) | ||||
|     }) | ||||
|     .bind(("::1", 8080))? | ||||
|     .run() | ||||
|  | ||||
							
								
								
									
										65
									
								
								backend-actix/src/request/authorization.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								backend-actix/src/request/authorization.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| use std::future::{Ready, ready}; | ||||
| 
 | ||||
| use actix_web::{FromRequest, http, HttpRequest, dev::Payload, web::Data}; | ||||
| use chrono::Utc; | ||||
| use jsonwebtoken::{encode, Header, EncodingKey, decode, DecodingKey, Validation}; | ||||
| use serde::{Serialize, Deserialize}; | ||||
| use uuid::Uuid; | ||||
| 
 | ||||
| use crate::{schema::user::{User, get_user}, DbPool}; | ||||
| 
 | ||||
| use super::error::ApiError; | ||||
| 
 | ||||
| #[derive(Debug, Serialize, Deserialize)] | ||||
| pub struct Claims { | ||||
|     exp: i64, | ||||
|     uid: Uuid | ||||
| } | ||||
| 
 | ||||
| fn get_claims(req: &HttpRequest) -> Result<Claims, ApiError>  { | ||||
|     let token = req.headers() | ||||
|         .get(http::header::AUTHORIZATION) | ||||
|         .map(|h| h.to_str().unwrap().split_at(7).1.to_string()); | ||||
| 
 | ||||
|     let token = token.ok_or(ApiError{ | ||||
|         status: 400, | ||||
|         message: "JWT-token was not specified in the Authorization header as Bearer: token".to_string() | ||||
|     })?; | ||||
| 
 | ||||
|     println!("{:?}", token); | ||||
| 
 | ||||
|     let secret = "secret"; | ||||
|     Ok(decode::<Claims>(token.as_str(), &DecodingKey::from_secret(secret.as_bytes()), &Validation::default())?.claims) | ||||
| } | ||||
| 
 | ||||
| pub fn get_token(user: &User) -> Result<String, ApiError> { | ||||
|     let claims = Claims { | ||||
|         exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), | ||||
|         uid: user.id, | ||||
|     }; | ||||
| 
 | ||||
|     println!("{:?}", claims); | ||||
| 
 | ||||
|     let secret = "secret"; | ||||
|     Ok(encode( | ||||
|         &Header::default(), | ||||
|         &claims, | ||||
|         &EncodingKey::from_secret(secret.as_bytes()))?) | ||||
| } | ||||
| 
 | ||||
| impl FromRequest for User { | ||||
|     type Error = ApiError; | ||||
|     type Future = Ready<Result<Self, Self::Error>>; | ||||
| 
 | ||||
|     fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { | ||||
|         ready( | ||||
|             (|| -> Result<User, ApiError>{ | ||||
|                 let pool = req.app_data::<Data<DbPool>>().expect("No database configured"); | ||||
|                 let mut conn = pool.get().expect("couldn't get db connection from pool"); | ||||
|                 let uid = get_claims(req)?.uid; | ||||
|                 
 | ||||
|                 Ok(get_user(&mut conn, uid)?) | ||||
|             })() | ||||
|         ) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								backend-actix/src/request/gamenight_handlers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								backend-actix/src/request/gamenight_handlers.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| use actix_web::{get, web, Responder, http::header::ContentType, HttpResponse}; | ||||
| 
 | ||||
| use crate::{DbPool, request::{error::ApiError, responses::GameNightResponse}, schema::{self, user::User}}; | ||||
| 
 | ||||
| #[get("/gamenights")] | ||||
| pub async fn gamenights(pool: web::Data<DbPool>, _user: User) -> Result<impl Responder, ApiError> { | ||||
|     let mut conn = pool.get().expect("couldn't get db connection from pool"); | ||||
|     let gamenights = schema::gamenights(&mut conn)?; | ||||
| 
 | ||||
|     Ok(HttpResponse::Ok() | ||||
|         .content_type(ContentType::json()) | ||||
|         .body(serde_json::to_string(&GameNightResponse { gamenights })?) | ||||
|     ) | ||||
| } | ||||
| @ -1,8 +1,11 @@ | ||||
| 
 | ||||
| mod requests; | ||||
| mod responses; | ||||
| mod handler; | ||||
| mod user_handlers; | ||||
| mod gamenight_handlers; | ||||
| mod error; | ||||
| mod authorization; | ||||
| 
 | ||||
| pub use handler::login; | ||||
| pub use handler::register; | ||||
| pub use user_handlers::login; | ||||
| pub use user_handlers::register; | ||||
| pub use gamenight_handlers::gamenights; | ||||
| @ -1,6 +1,8 @@ | ||||
| use serde::{Serialize, Deserialize}; | ||||
| use uuid::Uuid; | ||||
| 
 | ||||
| use crate::schema::gamenight::Gamenight; | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize)] | ||||
| pub struct LoginResponse { | ||||
|     pub login_result: bool, | ||||
| @ -27,4 +29,9 @@ impl LoginResponse { | ||||
|             jwt_token: None | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize)] | ||||
| pub struct GameNightResponse { | ||||
|     pub gamenights: Vec::<Gamenight> 
 | ||||
| } | ||||
| @ -1,18 +1,14 @@ | ||||
| 
 | ||||
| use actix_web::http::header::ContentType; | ||||
| use actix_web::{web, post, HttpResponse, Responder}; | ||||
| use chrono::Utc; | ||||
| use serde::{Serialize, Deserialize}; | ||||
| use uuid::Uuid; | ||||
| use actix_web::{web, post, HttpResponse, Responder, get}; | ||||
| use validator::ValidateArgs; | ||||
| use crate::DbPool; | ||||
| use crate::request::requests::{Login, Register}; | ||||
| use crate::request::error::ApiError; | ||||
| use crate::request::responses::LoginResponse; | ||||
| use crate::schema::user::Role; | ||||
| use crate::request::authorization::get_token; | ||||
| use crate::schema::{self}; | ||||
| use serde_json; | ||||
| use jsonwebtoken::{encode, EncodingKey, Header}; | ||||
| 
 | ||||
| impl Into<schema::user::LoginUser> for Login { | ||||
|     fn into(self) -> schema::user::LoginUser { | ||||
| @ -33,14 +29,9 @@ impl Into<schema::user::Register> for Register { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Serialize, Deserialize)] | ||||
| struct Claims { | ||||
|     exp: i64, | ||||
|     uid: Uuid, | ||||
|     role: Role, | ||||
| } | ||||
| 
 | ||||
| #[post("/login")] | ||||
| 
 | ||||
| #[get("/token")] | ||||
| pub async fn login(pool: web::Data<DbPool>, login_data: web::Json<Login>) -> Result<impl Responder, ApiError> { | ||||
|     let data = login_data.into_inner(); | ||||
| 
 | ||||
| @ -50,18 +41,7 @@ pub async fn login(pool: web::Data<DbPool>, login_data: web::Json<Login>) -> Res | ||||
|     }) | ||||
|     .await?? 
 | ||||
|     { | ||||
|         let my_claims = Claims { | ||||
|             exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), | ||||
|             uid: user.id, | ||||
|             role: user.role, | ||||
|         }; | ||||
|     
 | ||||
|         let secret = "secret"; | ||||
|         let token = encode( | ||||
|             &Header::default(), | ||||
|             &my_claims, | ||||
|             &EncodingKey::from_secret(secret.as_bytes()))?; | ||||
| 
 | ||||
|         let token = get_token(&user)?; | ||||
|         LoginResponse::success(user.id, token) | ||||
|     } | ||||
|     else { | ||||
| @ -74,7 +54,7 @@ pub async fn login(pool: web::Data<DbPool>, login_data: web::Json<Login>) -> Res | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| #[post("/register")] | ||||
| #[post("/user")] | ||||
| pub async fn register(pool: web::Data<DbPool>, register_data: web::Json<Register>) -> Result<impl Responder, ApiError> { | ||||
|     let data1 = register_data.clone(); | ||||
|     let data2 = register_data.clone(); | ||||
							
								
								
									
										20
									
								
								backend-actix/src/schema/gamenight.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								backend-actix/src/schema/gamenight.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| use chrono::{DateTime, Utc}; | ||||
| use diesel::{Insertable, Queryable, PgConnection, RunQueryDsl}; | ||||
| use serde::{Serialize, Deserialize}; | ||||
| use uuid::Uuid; | ||||
| use crate::schema::schema::gamenight; | ||||
| 
 | ||||
| use super::error::DatabaseError; | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize, Debug, Insertable, Queryable)] | ||||
| #[diesel(table_name = gamenight)] | ||||
| pub struct Gamenight { | ||||
|     pub id: Uuid, | ||||
|     pub name: String, | ||||
|     pub datetime: DateTime<Utc>, | ||||
|     pub owner_id: Uuid, | ||||
| } | ||||
| 
 | ||||
| pub fn gamenights(conn: &mut PgConnection, ) -> Result<Vec::<Gamenight>, DatabaseError> { | ||||
|     Ok(gamenight::table.load::<Gamenight>(conn)?) | ||||
| } | ||||
| @ -1,6 +1,8 @@ | ||||
| pub mod user; | ||||
| pub mod error; | ||||
| pub mod schema; | ||||
| pub mod gamenight; | ||||
| 
 | ||||
| pub use user::login; | ||||
| pub use user::register; | ||||
| pub use gamenight::gamenights; | ||||
|  | ||||
| @ -85,6 +85,10 @@ pub fn login(conn: &mut PgConnection, user: LoginUser) -> Result<Option<User>, D | ||||
|     } 
 | ||||
| } | ||||
| 
 | ||||
| pub fn get_user(conn: &mut PgConnection, id: Uuid) -> Result<User, DatabaseError> { | ||||
|     Ok(users::table.find(id).first(conn)?) | ||||
| } | ||||
| 
 | ||||
| pub fn unique_username(username: &String, conn: &mut PgConnection) -> Result<(), ValidationError> { | ||||
|     match users::table | ||||
|         .count() | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user