sa_token_plugin_actix_web/
adapter.rs1use actix_web::{HttpRequest, HttpResponse};
6use sa_token_adapter::context::{SaRequest, SaResponse, CookieOptions};
7use serde::Serialize;
8use std::collections::HashMap;
9
10pub struct ActixRequestAdapter<'a> {
12 request: &'a HttpRequest,
13}
14
15impl<'a> ActixRequestAdapter<'a> {
16 pub fn new(request: &'a HttpRequest) -> Self {
17 Self { request }
18 }
19}
20
21impl<'a> SaRequest for ActixRequestAdapter<'a> {
22 fn get_header(&self, name: &str) -> Option<String> {
23 self.request.headers().get(name)
24 .and_then(|v| v.to_str().ok())
25 .map(|s| s.to_string())
26 }
27
28 fn get_cookie(&self, name: &str) -> Option<String> {
29 self.request.cookie(name)
30 .map(|c| c.value().to_string())
31 }
32
33 fn get_param(&self, name: &str) -> Option<String> {
34 self.request.match_info().get(name)
37 .map(|s| s.to_string())
38 .or_else(|| {
39 parse_query_string(self.request.query_string())
41 .get(name)
42 .cloned()
43 })
44 }
45
46 fn get_path(&self) -> String {
47 self.request.path().to_string()
48 }
49
50 fn get_method(&self) -> String {
51 self.request.method().to_string()
52 }
53
54 fn get_client_ip(&self) -> Option<String> {
55 self.request.peer_addr()
56 .map(|addr| addr.ip().to_string())
57 }
58}
59
60pub struct ActixResponseAdapter {
62 status: actix_web::http::StatusCode,
63 headers: Vec<(String, String)>,
64 cookies: Vec<actix_web::cookie::Cookie<'static>>,
65 body: Option<String>,
66}
67
68impl ActixResponseAdapter {
69 pub fn new() -> Self {
70 Self {
71 status: actix_web::http::StatusCode::OK,
72 headers: Vec::new(),
73 cookies: Vec::new(),
74 body: None,
75 }
76 }
77
78 pub fn build(self) -> HttpResponse {
80 let mut builder = HttpResponse::build(self.status);
81
82 for (name, value) in self.headers {
83 builder.insert_header((name, value));
84 }
85
86 for cookie in self.cookies {
87 builder.cookie(cookie);
88 }
89
90 if let Some(body) = self.body {
91 builder.body(body)
92 } else {
93 builder.finish()
94 }
95 }
96}
97
98impl Default for ActixResponseAdapter {
99 fn default() -> Self {
100 Self::new()
101 }
102}
103
104impl SaResponse for ActixResponseAdapter {
105 fn set_header(&mut self, name: &str, value: &str) {
106 self.headers.push((name.to_string(), value.to_string()));
107 }
108
109 fn set_cookie(&mut self, name: &str, value: &str, options: CookieOptions) {
110 use actix_web::cookie::{Cookie, SameSite};
111
112 let mut cookie = Cookie::new(name.to_string(), value.to_string());
113
114 if let Some(domain) = options.domain {
115 cookie.set_domain(domain);
116 }
117 if let Some(path) = options.path {
118 cookie.set_path(path);
119 }
120 if let Some(max_age) = options.max_age {
121 cookie.set_max_age(actix_web::cookie::time::Duration::seconds(max_age));
122 }
123 cookie.set_http_only(options.http_only);
124 cookie.set_secure(options.secure);
125
126 if let Some(same_site) = options.same_site {
127 use sa_token_adapter::context::SameSite as SaSameSite;
128 let ss = match same_site {
129 SaSameSite::Strict => SameSite::Strict,
130 SaSameSite::Lax => SameSite::Lax,
131 SaSameSite::None => SameSite::None,
132 };
133 cookie.set_same_site(ss);
134 }
135
136 self.cookies.push(cookie);
137 }
138
139 fn set_status(&mut self, status: u16) {
140 if let Ok(status_code) = actix_web::http::StatusCode::from_u16(status) {
141 self.status = status_code;
142 }
143 }
144
145 fn set_json_body<T: Serialize>(&mut self, body: T) -> Result<(), serde_json::Error> {
146 let json = serde_json::to_string(&body)?;
147 self.body = Some(json);
148 self.headers.push(("Content-Type".to_string(), "application/json".to_string()));
149 Ok(())
150 }
151}
152
153fn parse_query_string(query: &str) -> HashMap<String, String> {
155 let mut params = HashMap::new();
156 for pair in query.split('&') {
157 if let Some((key, value)) = pair.split_once('=') {
158 if let Ok(decoded_value) = urlencoding::decode(value) {
159 params.insert(key.to_string(), decoded_value.to_string());
160 }
161 }
162 }
163 params
164}