Skip to main content

wae_session/
config.rs

1//! Session 配置模块
2//!
3//! 提供 Session 的配置选项。
4
5use std::time::Duration;
6
7/// Session 配置
8///
9/// 定义 Session 的各种配置选项。
10#[derive(Debug, Clone)]
11pub struct SessionConfig {
12    /// Session Cookie 名称
13    pub cookie_name: String,
14    /// Session Cookie 域
15    pub cookie_domain: Option<String>,
16    /// Session Cookie 路径
17    pub cookie_path: String,
18    /// 是否仅 HTTPS
19    pub cookie_secure: bool,
20    /// 是否 HttpOnly
21    pub cookie_http_only: bool,
22    /// SameSite 策略
23    pub cookie_same_site: SameSite,
24    /// Session 过期时间
25    pub ttl: Duration,
26    /// Session ID 长度
27    pub id_length: usize,
28    /// 签名密钥
29    pub secret_key: Option<String>,
30    /// 是否启用签名
31    pub signed: bool,
32}
33
34/// SameSite Cookie 策略
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum SameSite {
37    /// 严格模式:同站请求才发送 Cookie
38    Strict,
39    /// 宽松模式:跨站导航时发送 Cookie
40    Lax,
41    /// 无限制
42    None,
43}
44
45impl Default for SessionConfig {
46    fn default() -> Self {
47        Self {
48            cookie_name: "session".to_string(),
49            cookie_domain: None,
50            cookie_path: "/".to_string(),
51            cookie_secure: false,
52            cookie_http_only: true,
53            cookie_same_site: SameSite::Lax,
54            ttl: Duration::from_secs(3600),
55            id_length: 32,
56            secret_key: None,
57            signed: false,
58        }
59    }
60}
61
62impl SessionConfig {
63    /// 创建新的 Session 配置
64    pub fn new() -> Self {
65        Self::default()
66    }
67
68    /// 设置 Cookie 名称
69    pub fn with_cookie_name(mut self, name: impl Into<String>) -> Self {
70        self.cookie_name = name.into();
71        self
72    }
73
74    /// 设置 Cookie 域
75    pub fn with_cookie_domain(mut self, domain: impl Into<String>) -> Self {
76        self.cookie_domain = Some(domain.into());
77        self
78    }
79
80    /// 设置 Cookie 路径
81    pub fn with_cookie_path(mut self, path: impl Into<String>) -> Self {
82        self.cookie_path = path.into();
83        self
84    }
85
86    /// 设置是否仅 HTTPS
87    pub fn with_secure(mut self, secure: bool) -> Self {
88        self.cookie_secure = secure;
89        self
90    }
91
92    /// 设置是否 HttpOnly
93    pub fn with_http_only(mut self, http_only: bool) -> Self {
94        self.cookie_http_only = http_only;
95        self
96    }
97
98    /// 设置 SameSite 策略
99    pub fn with_same_site(mut self, same_site: SameSite) -> Self {
100        self.cookie_same_site = same_site;
101        self
102    }
103
104    /// 设置 Session 过期时间
105    pub fn with_ttl(mut self, ttl: Duration) -> Self {
106        self.ttl = ttl;
107        self
108    }
109
110    /// 设置 Session ID 长度
111    pub fn with_id_length(mut self, length: usize) -> Self {
112        self.id_length = length;
113        self
114    }
115
116    /// 设置签名密钥
117    pub fn with_secret_key(mut self, key: impl Into<String>) -> Self {
118        self.secret_key = Some(key.into());
119        self.signed = true;
120        self
121    }
122
123    /// 启用签名
124    pub fn signed(mut self, key: impl Into<String>) -> Self {
125        self.secret_key = Some(key.into());
126        self.signed = true;
127        self
128    }
129
130    /// 禁用签名
131    pub fn unsigned(mut self) -> Self {
132        self.secret_key = None;
133        self.signed = false;
134        self
135    }
136
137    /// 生成 Cookie 字符串
138    pub fn build_cookie_header(&self, session_id: &str) -> String {
139        let mut parts = vec![format!("{}={}", self.cookie_name, session_id)];
140
141        if let Some(ref domain) = self.cookie_domain {
142            parts.push(format!("Domain={}", domain));
143        }
144
145        parts.push(format!("Path={}", self.cookie_path));
146
147        if self.cookie_secure {
148            parts.push("Secure".to_string());
149        }
150
151        if self.cookie_http_only {
152            parts.push("HttpOnly".to_string());
153        }
154
155        let same_site = match self.cookie_same_site {
156            SameSite::Strict => "Strict",
157            SameSite::Lax => "Lax",
158            SameSite::None => "None",
159        };
160        parts.push(format!("SameSite={}", same_site));
161
162        let max_age = self.ttl.as_secs();
163        parts.push(format!("Max-Age={}", max_age));
164
165        parts.join("; ")
166    }
167}