1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-03-12 08:42:47 +01:00
actix-extras/src/actix_session/middleware.rs.html

933 lines
39 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-session/src/middleware.rs`."><meta name="keywords" content="rust, rustlang, rust-lang"><title>middleware.rs - source</title><link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/SourceSerif4-Regular-1f7d512b176f0f72.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/FiraSans-Regular-018c141bf0843ffd.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/FiraSans-Medium-8f9a781e4970d388.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/SourceSerif4-Bold-124a1ca42af929b6.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2"><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-ef244fc9943488f7.css" id="mainThemeStyle"><link rel="stylesheet" id="themeStyle" href="../../static.files/light-c11f492748536797.css"><link rel="stylesheet" disabled href="../../static.files/dark-a78f946771c40031.css"><link rel="stylesheet" disabled href="../../static.files/ayu-70b683d68cb31790.css"><script id="default-settings" ></script><script src="../../static.files/storage-d43fa987303ecbbb.js"></script><script defer src="../../static.files/source-script-74087aa2e88f4475.js"></script><script defer src="../../source-files.js"></script><script defer src="../../static.files/main-0dede64717b247ca.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-201a7e04dc4c6fce.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc source"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"></nav><main><div class="width-limiter"><nav class="sub"><a class="sub-logo-container" href="../../actix_session/index.html">
<img src="https://actix.rs/img/logo.png" alt="logo"></a><form class="search-form"><span></span><input class="search-input" name="search" autocomplete="off" spellcheck="false" placeholder="Click or press S to search, ? for more options…" type="search"><div id="help-button" title="help" tabindex="-1"><a href="../../help.html">?</a></div><div id="settings-menu" tabindex="-1"><a href="../../settings.html" title="settings"><img width="22" height="22" alt="Change settings" src="../../static.files/wheel-5ec35bf9ca753509.svg"></a></div></form></nav><section id="main-content" class="content"><div class="example-wrap"><pre class="src-line-numbers"><span id="1">1</span>
<span id="2">2</span>
<span id="3">3</span>
<span id="4">4</span>
<span id="5">5</span>
<span id="6">6</span>
<span id="7">7</span>
<span id="8">8</span>
<span id="9">9</span>
<span id="10">10</span>
<span id="11">11</span>
<span id="12">12</span>
<span id="13">13</span>
<span id="14">14</span>
<span id="15">15</span>
<span id="16">16</span>
<span id="17">17</span>
<span id="18">18</span>
<span id="19">19</span>
<span id="20">20</span>
<span id="21">21</span>
<span id="22">22</span>
<span id="23">23</span>
<span id="24">24</span>
<span id="25">25</span>
<span id="26">26</span>
<span id="27">27</span>
<span id="28">28</span>
<span id="29">29</span>
<span id="30">30</span>
<span id="31">31</span>
<span id="32">32</span>
<span id="33">33</span>
<span id="34">34</span>
<span id="35">35</span>
<span id="36">36</span>
<span id="37">37</span>
<span id="38">38</span>
<span id="39">39</span>
<span id="40">40</span>
<span id="41">41</span>
<span id="42">42</span>
<span id="43">43</span>
<span id="44">44</span>
<span id="45">45</span>
<span id="46">46</span>
<span id="47">47</span>
<span id="48">48</span>
<span id="49">49</span>
<span id="50">50</span>
<span id="51">51</span>
<span id="52">52</span>
<span id="53">53</span>
<span id="54">54</span>
<span id="55">55</span>
<span id="56">56</span>
<span id="57">57</span>
<span id="58">58</span>
<span id="59">59</span>
<span id="60">60</span>
<span id="61">61</span>
<span id="62">62</span>
<span id="63">63</span>
<span id="64">64</span>
<span id="65">65</span>
<span id="66">66</span>
<span id="67">67</span>
<span id="68">68</span>
<span id="69">69</span>
<span id="70">70</span>
<span id="71">71</span>
<span id="72">72</span>
<span id="73">73</span>
<span id="74">74</span>
<span id="75">75</span>
<span id="76">76</span>
<span id="77">77</span>
<span id="78">78</span>
<span id="79">79</span>
<span id="80">80</span>
<span id="81">81</span>
<span id="82">82</span>
<span id="83">83</span>
<span id="84">84</span>
<span id="85">85</span>
<span id="86">86</span>
<span id="87">87</span>
<span id="88">88</span>
<span id="89">89</span>
<span id="90">90</span>
<span id="91">91</span>
<span id="92">92</span>
<span id="93">93</span>
<span id="94">94</span>
<span id="95">95</span>
<span id="96">96</span>
<span id="97">97</span>
<span id="98">98</span>
<span id="99">99</span>
<span id="100">100</span>
<span id="101">101</span>
<span id="102">102</span>
<span id="103">103</span>
<span id="104">104</span>
<span id="105">105</span>
<span id="106">106</span>
<span id="107">107</span>
<span id="108">108</span>
<span id="109">109</span>
<span id="110">110</span>
<span id="111">111</span>
<span id="112">112</span>
<span id="113">113</span>
<span id="114">114</span>
<span id="115">115</span>
<span id="116">116</span>
<span id="117">117</span>
<span id="118">118</span>
<span id="119">119</span>
<span id="120">120</span>
<span id="121">121</span>
<span id="122">122</span>
<span id="123">123</span>
<span id="124">124</span>
<span id="125">125</span>
<span id="126">126</span>
<span id="127">127</span>
<span id="128">128</span>
<span id="129">129</span>
<span id="130">130</span>
<span id="131">131</span>
<span id="132">132</span>
<span id="133">133</span>
<span id="134">134</span>
<span id="135">135</span>
<span id="136">136</span>
<span id="137">137</span>
<span id="138">138</span>
<span id="139">139</span>
<span id="140">140</span>
<span id="141">141</span>
<span id="142">142</span>
<span id="143">143</span>
<span id="144">144</span>
<span id="145">145</span>
<span id="146">146</span>
<span id="147">147</span>
<span id="148">148</span>
<span id="149">149</span>
<span id="150">150</span>
<span id="151">151</span>
<span id="152">152</span>
<span id="153">153</span>
<span id="154">154</span>
<span id="155">155</span>
<span id="156">156</span>
<span id="157">157</span>
<span id="158">158</span>
<span id="159">159</span>
<span id="160">160</span>
<span id="161">161</span>
<span id="162">162</span>
<span id="163">163</span>
<span id="164">164</span>
<span id="165">165</span>
<span id="166">166</span>
<span id="167">167</span>
<span id="168">168</span>
<span id="169">169</span>
<span id="170">170</span>
<span id="171">171</span>
<span id="172">172</span>
<span id="173">173</span>
<span id="174">174</span>
<span id="175">175</span>
<span id="176">176</span>
<span id="177">177</span>
<span id="178">178</span>
<span id="179">179</span>
<span id="180">180</span>
<span id="181">181</span>
<span id="182">182</span>
<span id="183">183</span>
<span id="184">184</span>
<span id="185">185</span>
<span id="186">186</span>
<span id="187">187</span>
<span id="188">188</span>
<span id="189">189</span>
<span id="190">190</span>
<span id="191">191</span>
<span id="192">192</span>
<span id="193">193</span>
<span id="194">194</span>
<span id="195">195</span>
<span id="196">196</span>
<span id="197">197</span>
<span id="198">198</span>
<span id="199">199</span>
<span id="200">200</span>
<span id="201">201</span>
<span id="202">202</span>
<span id="203">203</span>
<span id="204">204</span>
<span id="205">205</span>
<span id="206">206</span>
<span id="207">207</span>
<span id="208">208</span>
<span id="209">209</span>
<span id="210">210</span>
<span id="211">211</span>
<span id="212">212</span>
<span id="213">213</span>
<span id="214">214</span>
<span id="215">215</span>
<span id="216">216</span>
<span id="217">217</span>
<span id="218">218</span>
<span id="219">219</span>
<span id="220">220</span>
<span id="221">221</span>
<span id="222">222</span>
<span id="223">223</span>
<span id="224">224</span>
<span id="225">225</span>
<span id="226">226</span>
<span id="227">227</span>
<span id="228">228</span>
<span id="229">229</span>
<span id="230">230</span>
<span id="231">231</span>
<span id="232">232</span>
<span id="233">233</span>
<span id="234">234</span>
<span id="235">235</span>
<span id="236">236</span>
<span id="237">237</span>
<span id="238">238</span>
<span id="239">239</span>
<span id="240">240</span>
<span id="241">241</span>
<span id="242">242</span>
<span id="243">243</span>
<span id="244">244</span>
<span id="245">245</span>
<span id="246">246</span>
<span id="247">247</span>
<span id="248">248</span>
<span id="249">249</span>
<span id="250">250</span>
<span id="251">251</span>
<span id="252">252</span>
<span id="253">253</span>
<span id="254">254</span>
<span id="255">255</span>
<span id="256">256</span>
<span id="257">257</span>
<span id="258">258</span>
<span id="259">259</span>
<span id="260">260</span>
<span id="261">261</span>
<span id="262">262</span>
<span id="263">263</span>
<span id="264">264</span>
<span id="265">265</span>
<span id="266">266</span>
<span id="267">267</span>
<span id="268">268</span>
<span id="269">269</span>
<span id="270">270</span>
<span id="271">271</span>
<span id="272">272</span>
<span id="273">273</span>
<span id="274">274</span>
<span id="275">275</span>
<span id="276">276</span>
<span id="277">277</span>
<span id="278">278</span>
<span id="279">279</span>
<span id="280">280</span>
<span id="281">281</span>
<span id="282">282</span>
<span id="283">283</span>
<span id="284">284</span>
<span id="285">285</span>
<span id="286">286</span>
<span id="287">287</span>
<span id="288">288</span>
<span id="289">289</span>
<span id="290">290</span>
<span id="291">291</span>
<span id="292">292</span>
<span id="293">293</span>
<span id="294">294</span>
<span id="295">295</span>
<span id="296">296</span>
<span id="297">297</span>
<span id="298">298</span>
<span id="299">299</span>
<span id="300">300</span>
<span id="301">301</span>
<span id="302">302</span>
<span id="303">303</span>
<span id="304">304</span>
<span id="305">305</span>
<span id="306">306</span>
<span id="307">307</span>
<span id="308">308</span>
<span id="309">309</span>
<span id="310">310</span>
<span id="311">311</span>
<span id="312">312</span>
<span id="313">313</span>
<span id="314">314</span>
<span id="315">315</span>
<span id="316">316</span>
<span id="317">317</span>
<span id="318">318</span>
<span id="319">319</span>
<span id="320">320</span>
<span id="321">321</span>
<span id="322">322</span>
<span id="323">323</span>
<span id="324">324</span>
<span id="325">325</span>
<span id="326">326</span>
<span id="327">327</span>
<span id="328">328</span>
<span id="329">329</span>
<span id="330">330</span>
<span id="331">331</span>
<span id="332">332</span>
<span id="333">333</span>
<span id="334">334</span>
<span id="335">335</span>
<span id="336">336</span>
<span id="337">337</span>
<span id="338">338</span>
<span id="339">339</span>
<span id="340">340</span>
<span id="341">341</span>
<span id="342">342</span>
<span id="343">343</span>
<span id="344">344</span>
<span id="345">345</span>
<span id="346">346</span>
<span id="347">347</span>
<span id="348">348</span>
<span id="349">349</span>
<span id="350">350</span>
<span id="351">351</span>
<span id="352">352</span>
<span id="353">353</span>
<span id="354">354</span>
<span id="355">355</span>
<span id="356">356</span>
<span id="357">357</span>
<span id="358">358</span>
<span id="359">359</span>
<span id="360">360</span>
<span id="361">361</span>
<span id="362">362</span>
<span id="363">363</span>
<span id="364">364</span>
<span id="365">365</span>
<span id="366">366</span>
<span id="367">367</span>
<span id="368">368</span>
<span id="369">369</span>
<span id="370">370</span>
<span id="371">371</span>
<span id="372">372</span>
<span id="373">373</span>
<span id="374">374</span>
<span id="375">375</span>
<span id="376">376</span>
<span id="377">377</span>
<span id="378">378</span>
<span id="379">379</span>
<span id="380">380</span>
<span id="381">381</span>
<span id="382">382</span>
<span id="383">383</span>
<span id="384">384</span>
<span id="385">385</span>
<span id="386">386</span>
<span id="387">387</span>
<span id="388">388</span>
<span id="389">389</span>
<span id="390">390</span>
<span id="391">391</span>
<span id="392">392</span>
<span id="393">393</span>
<span id="394">394</span>
<span id="395">395</span>
<span id="396">396</span>
<span id="397">397</span>
<span id="398">398</span>
<span id="399">399</span>
<span id="400">400</span>
<span id="401">401</span>
<span id="402">402</span>
<span id="403">403</span>
<span id="404">404</span>
<span id="405">405</span>
<span id="406">406</span>
<span id="407">407</span>
<span id="408">408</span>
<span id="409">409</span>
<span id="410">410</span>
<span id="411">411</span>
<span id="412">412</span>
<span id="413">413</span>
<span id="414">414</span>
<span id="415">415</span>
<span id="416">416</span>
<span id="417">417</span>
<span id="418">418</span>
<span id="419">419</span>
<span id="420">420</span>
<span id="421">421</span>
<span id="422">422</span>
<span id="423">423</span>
<span id="424">424</span>
<span id="425">425</span>
<span id="426">426</span>
<span id="427">427</span>
<span id="428">428</span>
<span id="429">429</span>
<span id="430">430</span>
<span id="431">431</span>
<span id="432">432</span>
<span id="433">433</span>
<span id="434">434</span>
<span id="435">435</span>
<span id="436">436</span>
<span id="437">437</span>
<span id="438">438</span>
<span id="439">439</span>
<span id="440">440</span>
<span id="441">441</span>
<span id="442">442</span>
<span id="443">443</span>
<span id="444">444</span>
<span id="445">445</span>
<span id="446">446</span>
<span id="447">447</span>
<span id="448">448</span>
<span id="449">449</span>
<span id="450">450</span>
<span id="451">451</span>
<span id="452">452</span>
<span id="453">453</span>
<span id="454">454</span>
<span id="455">455</span>
<span id="456">456</span>
<span id="457">457</span>
<span id="458">458</span>
<span id="459">459</span>
<span id="460">460</span>
<span id="461">461</span>
<span id="462">462</span>
<span id="463">463</span>
<span id="464">464</span>
<span id="465">465</span>
</pre><pre class="rust"><code><span class="kw">use </span>std::{collections::HashMap, convert::TryInto, fmt, future::Future, pin::Pin, rc::Rc};
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{
body::MessageBody,
cookie::{Cookie, CookieJar, Key},
dev::{forward_ready, ResponseHead, Service, ServiceRequest, ServiceResponse, Transform},
http::header::{HeaderValue, SET_COOKIE},
HttpResponse,
};
<span class="kw">use </span>anyhow::Context;
<span class="kw">use crate</span>::{
config::{
<span class="self">self</span>, Configuration, CookieConfiguration, CookieContentSecurity, SessionMiddlewareBuilder,
TtlExtensionPolicy,
},
storage::{LoadError, SessionKey, SessionStore},
Session, SessionStatus,
};
<span class="doccomment">/// A middleware for session management in Actix Web applications.
///
/// [`SessionMiddleware`] takes care of a few jobs:
///
/// - Instructs the session storage backend to create/update/delete/retrieve the state attached to
/// a session according to its status and the operations that have been performed against it;
/// - Set/remove a cookie, on the client side, to enable a user to be consistently associated with
/// the same session across multiple HTTP requests.
///
/// Use [`SessionMiddleware::new`] to initialize the session framework using the default parameters.
/// To create a new instance of [`SessionMiddleware`] you need to provide:
///
/// - an instance of the session storage backend you wish to use (i.e. an implementation of
/// [`SessionStore`]);
/// - a secret key, to sign or encrypt the content of client-side session cookie.
///
/// # How did we choose defaults?
/// You should not regret adding `actix-session` to your dependencies and going to production using
/// the default configuration. That is why, when in doubt, we opt to use the most secure option for
/// each configuration parameter.
///
/// We expose knobs to change the default to suit your needs—i.e., if you know what you are doing,
/// we will not stop you. But being a subject-matter expert should not be a requirement to deploy
/// reasonably secure implementation of sessions.
///
/// # Examples
/// ```no_run
/// use actix_web::{web, App, HttpServer, HttpResponse, Error};
/// use actix_session::{Session, SessionMiddleware, storage::RedisActorSessionStore};
/// use actix_web::cookie::Key;
///
/// // The secret key would usually be read from a configuration file/environment variables.
/// fn get_secret_key() -&gt; Key {
/// # todo!()
/// // [...]
/// }
///
/// #[actix_web::main]
/// async fn main() -&gt; std::io::Result&lt;()&gt; {
/// let secret_key = get_secret_key();
/// let redis_connection_string = &quot;127.0.0.1:6379&quot;;
/// HttpServer::new(move ||
/// App::new()
/// // Add session management to your application using Redis for session state storage
/// .wrap(
/// SessionMiddleware::new(
/// RedisActorSessionStore::new(redis_connection_string),
/// secret_key.clone()
/// )
/// )
/// .default_service(web::to(|| HttpResponse::Ok())))
/// .bind((&quot;127.0.0.1&quot;, 8080))?
/// .run()
/// .await
/// }
/// ```
///
/// If you want to customise use [`builder`](Self::builder) instead of [`new`](Self::new):
///
/// ```no_run
/// use actix_web::{App, cookie::{Key, time}, Error, HttpResponse, HttpServer, web};
/// use actix_session::{Session, SessionMiddleware, storage::RedisActorSessionStore};
/// use actix_session::config::PersistentSession;
///
/// // The secret key would usually be read from a configuration file/environment variables.
/// fn get_secret_key() -&gt; Key {
/// # todo!()
/// // [...]
/// }
///
/// #[actix_web::main]
/// async fn main() -&gt; std::io::Result&lt;()&gt; {
/// let secret_key = get_secret_key();
/// let redis_connection_string = &quot;127.0.0.1:6379&quot;;
/// HttpServer::new(move ||
/// App::new()
/// // Customise session length!
/// .wrap(
/// SessionMiddleware::builder(
/// RedisActorSessionStore::new(redis_connection_string),
/// secret_key.clone()
/// )
/// .session_lifecycle(
/// PersistentSession::default()
/// .session_ttl(time::Duration::days(5))
/// )
/// .build(),
/// )
/// .default_service(web::to(|| HttpResponse::Ok())))
/// .bind((&quot;127.0.0.1&quot;, 8080))?
/// .run()
/// .await
/// }
/// ```
</span><span class="attr">#[derive(Clone)]
</span><span class="kw">pub struct </span>SessionMiddleware&lt;Store: SessionStore&gt; {
storage_backend: Rc&lt;Store&gt;,
configuration: Rc&lt;Configuration&gt;,
}
<span class="kw">impl</span>&lt;Store: SessionStore&gt; SessionMiddleware&lt;Store&gt; {
<span class="doccomment">/// Use [`SessionMiddleware::new`] to initialize the session framework using the default
/// parameters.
///
/// To create a new instance of [`SessionMiddleware`] you need to provide:
/// - an instance of the session storage backend you wish to use (i.e. an implementation of
/// [`SessionStore`]);
/// - a secret key, to sign or encrypt the content of client-side session cookie.
</span><span class="kw">pub fn </span>new(store: Store, key: Key) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::builder(store, key).build()
}
<span class="doccomment">/// A fluent API to configure [`SessionMiddleware`].
///
/// It takes as input the two required inputs to create a new instance of [`SessionMiddleware`]:
/// - an instance of the session storage backend you wish to use (i.e. an implementation of
/// [`SessionStore`]);
/// - a secret key, to sign or encrypt the content of client-side session cookie.
</span><span class="kw">pub fn </span>builder(store: Store, key: Key) -&gt; SessionMiddlewareBuilder&lt;Store&gt; {
SessionMiddlewareBuilder::new(store, config::default_configuration(key))
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>from_parts(store: Store, configuration: Configuration) -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
storage_backend: Rc::new(store),
configuration: Rc::new(configuration),
}
}
}
<span class="kw">impl</span>&lt;S, B, Store&gt; Transform&lt;S, ServiceRequest&gt; <span class="kw">for </span>SessionMiddleware&lt;Store&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = actix_web::Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
B: MessageBody + <span class="lifetime">&#39;static</span>,
Store: SessionStore + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type </span>Response = ServiceResponse&lt;B&gt;;
<span class="kw">type </span>Error = actix_web::Error;
<span class="kw">type </span>Transform = InnerSessionMiddleware&lt;S, Store&gt;;
<span class="kw">type </span>InitError = ();
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Transform, <span class="self">Self</span>::InitError&gt;&gt;;
<span class="kw">fn </span>new_transform(<span class="kw-2">&amp;</span><span class="self">self</span>, service: S) -&gt; <span class="self">Self</span>::Future {
ready(<span class="prelude-val">Ok</span>(InnerSessionMiddleware {
service: Rc::new(service),
configuration: Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.configuration),
storage_backend: Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.storage_backend),
}))
}
}
<span class="doccomment">/// Short-hand to create an `actix_web::Error` instance that will result in an `Internal Server
/// Error` response while preserving the error root cause (e.g. in logs).
</span><span class="kw">fn </span>e500&lt;E: fmt::Debug + fmt::Display + <span class="lifetime">&#39;static</span>&gt;(err: E) -&gt; actix_web::Error {
<span class="comment">// We do not use `actix_web::error::ErrorInternalServerError` because we do not want to
// leak internal implementation details to the caller.
//
// `actix_web::error::ErrorInternalServerError` includes the error Display representation
// as body of the error responses, leading to messages like &quot;There was an issue persisting
// the session state&quot; reaching API clients. We don&#39;t want that, we want opaque 500s.
</span>actix_web::error::InternalError::from_response(
err,
HttpResponse::InternalServerError().finish(),
)
.into()
}
<span class="attr">#[doc(hidden)]
#[non_exhaustive]
</span><span class="kw">pub struct </span>InnerSessionMiddleware&lt;S, Store: SessionStore + <span class="lifetime">&#39;static</span>&gt; {
service: Rc&lt;S&gt;,
configuration: Rc&lt;Configuration&gt;,
storage_backend: Rc&lt;Store&gt;,
}
<span class="kw">impl</span>&lt;S, B, Store&gt; Service&lt;ServiceRequest&gt; <span class="kw">for </span>InnerSessionMiddleware&lt;S, Store&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = actix_web::Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
Store: SessionStore + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type </span>Response = ServiceResponse&lt;B&gt;;
<span class="kw">type </span>Error = actix_web::Error;
<span class="attr">#[allow(clippy::type_complexity)]
</span><span class="kw">type </span>Future = Pin&lt;Box&lt;<span class="kw">dyn </span>Future&lt;Output = <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Response, <span class="self">Self</span>::Error&gt;&gt;&gt;&gt;;
<span class="macro">forward_ready!</span>(service);
<span class="kw">fn </span>call(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw-2">mut </span>req: ServiceRequest) -&gt; <span class="self">Self</span>::Future {
<span class="kw">let </span>service = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.service);
<span class="kw">let </span>storage_backend = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.storage_backend);
<span class="kw">let </span>configuration = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.configuration);
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>session_key = extract_session_key(<span class="kw-2">&amp;</span>req, <span class="kw-2">&amp;</span>configuration.cookie);
<span class="kw">let </span>(session_key, session_state) =
load_session_state(session_key, storage_backend.as_ref()).<span class="kw">await</span><span class="question-mark">?</span>;
Session::set_session(<span class="kw-2">&amp;mut </span>req, session_state);
<span class="kw">let </span><span class="kw-2">mut </span>res = service.call(req).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let </span>(status, session_state) = Session::get_changes(<span class="kw-2">&amp;mut </span>res);
<span class="kw">match </span>session_key {
<span class="prelude-val">None </span>=&gt; {
<span class="comment">// we do not create an entry in the session store if there is no state attached
// to a fresh session
</span><span class="kw">if </span>!session_state.is_empty() {
<span class="kw">let </span>session_key = storage_backend
.save(session_state, <span class="kw-2">&amp;</span>configuration.session.state_ttl)
.<span class="kw">await
</span>.map_err(e500)<span class="question-mark">?</span>;
set_session_cookie(
res.response_mut().head_mut(),
session_key,
<span class="kw-2">&amp;</span>configuration.cookie,
)
.map_err(e500)<span class="question-mark">?</span>;
}
}
<span class="prelude-val">Some</span>(session_key) =&gt; {
<span class="kw">match </span>status {
SessionStatus::Changed =&gt; {
<span class="kw">let </span>session_key = storage_backend
.update(
session_key,
session_state,
<span class="kw-2">&amp;</span>configuration.session.state_ttl,
)
.<span class="kw">await
</span>.map_err(e500)<span class="question-mark">?</span>;
set_session_cookie(
res.response_mut().head_mut(),
session_key,
<span class="kw-2">&amp;</span>configuration.cookie,
)
.map_err(e500)<span class="question-mark">?</span>;
}
SessionStatus::Purged =&gt; {
storage_backend.delete(<span class="kw-2">&amp;</span>session_key).<span class="kw">await</span>.map_err(e500)<span class="question-mark">?</span>;
delete_session_cookie(
res.response_mut().head_mut(),
<span class="kw-2">&amp;</span>configuration.cookie,
)
.map_err(e500)<span class="question-mark">?</span>;
}
SessionStatus::Renewed =&gt; {
storage_backend.delete(<span class="kw-2">&amp;</span>session_key).<span class="kw">await</span>.map_err(e500)<span class="question-mark">?</span>;
<span class="kw">let </span>session_key = storage_backend
.save(session_state, <span class="kw-2">&amp;</span>configuration.session.state_ttl)
.<span class="kw">await
</span>.map_err(e500)<span class="question-mark">?</span>;
set_session_cookie(
res.response_mut().head_mut(),
session_key,
<span class="kw-2">&amp;</span>configuration.cookie,
)
.map_err(e500)<span class="question-mark">?</span>;
}
SessionStatus::Unchanged =&gt; {
<span class="kw">if </span><span class="macro">matches!</span>(
configuration.ttl_extension_policy,
TtlExtensionPolicy::OnEveryRequest
) {
storage_backend
.update_ttl(<span class="kw-2">&amp;</span>session_key, <span class="kw-2">&amp;</span>configuration.session.state_ttl)
.<span class="kw">await
</span>.map_err(e500)<span class="question-mark">?</span>;
<span class="kw">if </span>configuration.cookie.max_age.is_some() {
set_session_cookie(
res.response_mut().head_mut(),
session_key,
<span class="kw-2">&amp;</span>configuration.cookie,
)
.map_err(e500)<span class="question-mark">?</span>;
}
}
}
};
}
}
<span class="prelude-val">Ok</span>(res)
})
}
}
<span class="doccomment">/// Examines the session cookie attached to the incoming request, if there is one, and tries
/// to extract the session key.
///
/// It returns `None` if there is no session cookie or if the session cookie is considered invalid
/// (e.g., when failing a signature check).
</span><span class="kw">fn </span>extract_session_key(req: <span class="kw-2">&amp;</span>ServiceRequest, config: <span class="kw-2">&amp;</span>CookieConfiguration) -&gt; <span class="prelude-ty">Option</span>&lt;SessionKey&gt; {
<span class="kw">let </span>cookies = req.cookies().ok()<span class="question-mark">?</span>;
<span class="kw">let </span>session_cookie = cookies
.iter()
.find(|<span class="kw-2">&amp;</span>cookie| cookie.name() == config.name)<span class="question-mark">?</span>;
<span class="kw">let </span><span class="kw-2">mut </span>jar = CookieJar::new();
jar.add_original(session_cookie.clone());
<span class="kw">let </span>verification_result = <span class="kw">match </span>config.content_security {
CookieContentSecurity::Signed =&gt; jar.signed(<span class="kw-2">&amp;</span>config.key).get(<span class="kw-2">&amp;</span>config.name),
CookieContentSecurity::Private =&gt; jar.private(<span class="kw-2">&amp;</span>config.key).get(<span class="kw-2">&amp;</span>config.name),
};
<span class="kw">if </span>verification_result.is_none() {
<span class="macro">tracing::warn!</span>(
<span class="string">&quot;The session cookie attached to the incoming request failed to pass cryptographic \
checks (signature verification/decryption).&quot;
</span>);
}
<span class="kw">match </span>verification_result<span class="question-mark">?</span>.value().to_owned().try_into() {
<span class="prelude-val">Ok</span>(session_key) =&gt; <span class="prelude-val">Some</span>(session_key),
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">tracing::warn!</span>(
error.message = %err,
error.cause_chain = <span class="question-mark">?</span>err,
<span class="string">&quot;Invalid session key, ignoring.&quot;
</span>);
<span class="prelude-val">None
</span>}
}
}
<span class="kw">async fn </span>load_session_state&lt;Store: SessionStore&gt;(
session_key: <span class="prelude-ty">Option</span>&lt;SessionKey&gt;,
storage_backend: <span class="kw-2">&amp;</span>Store,
) -&gt; <span class="prelude-ty">Result</span>&lt;(<span class="prelude-ty">Option</span>&lt;SessionKey&gt;, HashMap&lt;String, String&gt;), actix_web::Error&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(session_key) = session_key {
<span class="kw">match </span>storage_backend.load(<span class="kw-2">&amp;</span>session_key).<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(state) =&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(state) = state {
<span class="prelude-val">Ok</span>((<span class="prelude-val">Some</span>(session_key), state))
} <span class="kw">else </span>{
<span class="comment">// We discard the existing session key given that the state attached to it can
// no longer be found (e.g. it expired or we suffered some data loss in the
// storage). Regenerating the session key will trigger the `save` workflow
// instead of the `update` workflow if the session state is modified during the
// lifecycle of the current request.
</span><span class="macro">tracing::info!</span>(
<span class="string">&quot;No session state has been found for a valid session key, creating a new \
empty session.&quot;
</span>);
<span class="prelude-val">Ok</span>((<span class="prelude-val">None</span>, HashMap::new()))
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="kw">match </span>err {
LoadError::Deserialization(err) =&gt; {
<span class="macro">tracing::warn!</span>(
error.message = %err,
error.cause_chain = <span class="question-mark">?</span>err,
<span class="string">&quot;Invalid session state, creating a new empty session.&quot;
</span>);
<span class="prelude-val">Ok</span>((<span class="prelude-val">Some</span>(session_key), HashMap::new()))
}
LoadError::Other(err) =&gt; <span class="prelude-val">Err</span>(e500(err)),
},
}
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>((<span class="prelude-val">None</span>, HashMap::new()))
}
}
<span class="kw">fn </span>set_session_cookie(
response: <span class="kw-2">&amp;mut </span>ResponseHead,
session_key: SessionKey,
config: <span class="kw-2">&amp;</span>CookieConfiguration,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt; {
<span class="kw">let </span>value: String = session_key.into();
<span class="kw">let </span><span class="kw-2">mut </span>cookie = Cookie::new(config.name.clone(), value);
cookie.set_secure(config.secure);
cookie.set_http_only(config.http_only);
cookie.set_same_site(config.same_site);
cookie.set_path(config.path.clone());
<span class="kw">if let </span><span class="prelude-val">Some</span>(max_age) = config.max_age {
cookie.set_max_age(max_age);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>domain) = config.domain {
cookie.set_domain(domain.clone());
}
<span class="kw">let </span><span class="kw-2">mut </span>jar = CookieJar::new();
<span class="kw">match </span>config.content_security {
CookieContentSecurity::Signed =&gt; jar.signed_mut(<span class="kw-2">&amp;</span>config.key).add(cookie),
CookieContentSecurity::Private =&gt; jar.private_mut(<span class="kw-2">&amp;</span>config.key).add(cookie),
}
<span class="comment">// set cookie
</span><span class="kw">let </span>cookie = jar.delta().next().unwrap();
<span class="kw">let </span>val = HeaderValue::from_str(<span class="kw-2">&amp;</span>cookie.encoded().to_string())
.context(<span class="string">&quot;Failed to attach a session cookie to the outgoing response&quot;</span>)<span class="question-mark">?</span>;
response.headers_mut().append(SET_COOKIE, val);
<span class="prelude-val">Ok</span>(())
}
<span class="kw">fn </span>delete_session_cookie(
response: <span class="kw-2">&amp;mut </span>ResponseHead,
config: <span class="kw-2">&amp;</span>CookieConfiguration,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt; {
<span class="kw">let </span>removal_cookie = Cookie::build(config.name.clone(), <span class="string">&quot;&quot;</span>)
.path(config.path.clone())
.secure(config.secure)
.http_only(config.http_only)
.same_site(config.same_site);
<span class="kw">let </span><span class="kw-2">mut </span>removal_cookie = <span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>domain) = config.domain {
removal_cookie.domain(domain)
} <span class="kw">else </span>{
removal_cookie
}
.finish();
removal_cookie.make_removal();
<span class="kw">let </span>val = HeaderValue::from_str(<span class="kw-2">&amp;</span>removal_cookie.to_string())
.context(<span class="string">&quot;Failed to attach a session removal cookie to the outgoing response&quot;</span>)<span class="question-mark">?</span>;
response.headers_mut().append(SET_COOKIE, val);
<span class="prelude-val">Ok</span>(())
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_session" data-themes="" data-resource-suffix="" data-rustdoc-version="1.67.0-nightly (73c9eaf21 2022-11-07)" data-search-js="search-39ee4160c7dc16c9.js" data-settings-js="settings-3a0b9947ba1bd99a.js" data-settings-css="settings-a66f7524084a489a.css" ></div></body></html>