1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! A loginmanager for actix-web
//!
//! ## Example
//! ```rust
//! use std::pin::Pin;
//! use actix_web::{get, web, App, HttpRequest, HttpResponse, HttpServer};
//! use actix_loginmanager as loginmanager;
//! use loginmanager::{CookieSession, LoginManager, UserMinix, UserWrap};
//! 
//! use futures::Future;
//! use loginmanager_codegen::login_required;
//! 
//! use futures::{future, future::Ready};
//!
//! #[derive(Clone)]
//! struct User {
//!     id: i32,
//!     name: &'static str,
//! }
//!
//! impl UserMinix for User {
//!     type Future = Pin<Box<dyn Future<Output = Option<Self>>>>;
//!     type Key = i32;
//!     fn get_user(i: &Self::Key, _: &HttpRequest) -> Self::Future {
//!         // let req = req.clone();
//!         let i = i.clone();
//!         Box::pin(async move {
//!             for id in 0..USERS.len() {
//!                 if USERS[id].id == i {
//!                     return Some(USERS[id].clone());
//!                 }
//!             }
//!             None
//!         })
//!     }
//! 
//!     fn get_id(&self) -> &Self::Key {
//!         &self.id
//!     }
//! }
//!
//! const USERS: [User; 3] = [
//!     User { id: 1, name: "Tom" },
//!     User { id: 2, name: "Jerry" },
//!     User { id: 3, name: "Spike" },
//! ];
//!
//! #[login_required(User)]
//! async fn hello() -> impl actix_web::Responder {
//!     return format!("hello {}",user.name);
//! }
//! 
//! async fn auto_login(req: HttpRequest) -> impl actix_web::Responder {
//!     let user = UserWrap::from(USERS[0].clone());
//!     loginmanager::login(&user, &req);
//!     HttpResponse::Ok().body(format!("login:{:?} ", user.user().name))
//! }
//! 
//! async fn logout(req: HttpRequest, UserWrap(user): UserWrap<User>) -> impl actix_web::Responder {
//!     loginmanager::logout(&user, &req);
//!     HttpResponse::Ok().body(format!("logout:{:?} ", user.name))
//! }
//! 
//! #[get("/")]
//! async fn index(UserWrap(user): UserWrap<User>) -> impl actix_web::Responder {
//!     HttpResponse::Ok().body(format!(
//!         "Hello:{:?} is_authenticated:{}",
//!         user.name,
//!         user.is_authenticated()
//!     ))
//! }
//! 
//! #[actix_web::main]
//! #[test]
//! async fn main() {
//!     HttpServer::new(|| {
//!         App::new()
//!             .wrap(LoginManager::new(
//!                 CookieSession::new(&[0; 32]).secure(false),
//!             ))
//!             .service(index)
//!             .route("/hello", web::get().to(hello))
//!             .route("/login", web::get().to(auto_login))
//!             .route("/logout", web::get().to(logout))
//!     })
//!     .bind("0.0.0.0:7081")
//!     .unwrap()
//!     .run()
//!     .await
//!     .unwrap();
//! }
//! ```

mod cooke_session;
mod loginmanager;
mod user;
pub use crate::cooke_session::CookieSession;
pub use crate::loginmanager::{DecodeRequest, LoginInfo, LoginManager, LoginState};
pub use crate::user::{UserMinix, UserWrap, UserWrapAuth};
use actix_web::HttpMessage;
pub use loginmanager_codegen::login_required;

/// The method of user login
pub fn login<U>(user: &dyn AsRef<U>, req: &actix_web::HttpRequest)
where
    U: 'static + UserMinix,
{
    let mut extensions = req.extensions_mut();
    let id = user.as_ref().get_id();
    let id_str = serde_json::to_string(&id).ok();
    extensions.insert(LoginInfo::new(id_str, LoginState::Login));
}

/// The method of user logout
pub fn logout<U>(user: &dyn AsRef<U>, req: &actix_web::HttpRequest)
where
    U: 'static + UserMinix,
{
    let mut extensions = req.extensions_mut();
    let id = user.as_ref().get_id();
    let id_str = serde_json::to_string(&id).ok();
    extensions.insert(LoginInfo::new(id_str, LoginState::Logout));
}