1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-03-28 23:18:40 +01:00

1368 lines
95 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/lib.rs`."><meta name="keywords" content="rust, rustlang, rust-lang"><title>lib.rs - source</title><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceSerif4-Regular.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../FiraSans-Regular.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../FiraSans-Medium.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceCodePro-Regular.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceSerif4-Bold.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceCodePro-Semibold.ttf.woff2"><link rel="stylesheet" type="text/css" href="../../normalize.css"><link rel="stylesheet" type="text/css" href="../../rustdoc.css" id="mainThemeStyle"><link rel="stylesheet" type="text/css" href="../../ayu.css" disabled><link rel="stylesheet" type="text/css" href="../../dark.css" disabled><link rel="stylesheet" type="text/css" href="../../light.css" id="themeStyle"><script id="default-settings" ></script><script src="../../storage.js"></script><script src="../../crates.js"></script><script defer src="../../main.js"></script><script defer src="../../source-script.js"></script><script defer src="../../source-files.js"></script>
<noscript><link rel="stylesheet" href="../../noscript.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="mobile-topbar"><button class="sidebar-menu-toggle">&#9776;</button><a class="sidebar-logo" href="../../actix_session/index.html"><div class="logo-container"><img src="https://actix.rs/img/logo.png" alt="logo"></div>
</a><h2 class="location"></h2>
</nav>
<nav class="sidebar"><a class="sidebar-logo" href="../../actix_session/index.html"><div class="logo-container">
<img src="https://actix.rs/img/logo.png" alt="logo"></div>
</a></nav><main><div class="width-limiter"><div class="sub-container"><a class="sub-logo-container" href="../../actix_session/index.html">
<img src="https://actix.rs/img/logo.png" alt="logo"></a><nav class="sub"><div class="theme-picker hidden"><button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"><img width="22" height="22" alt="Pick another theme!" src="../../brush.svg"></button><div id="theme-choices" role="menu"></div></div><form class="search-form"><div class="search-container"><span></span><input class="search-input" name="search" autocomplete="off" spellcheck="false" placeholder="Click or press S to search, ? for more options…" type="search"><button type="button" id="help-button" title="help">?</button><a id="settings-menu" href="../../settings.html" title="settings"><img width="22" height="22" alt="Change settings" src="../../wheel.svg"></a></div></form></nav></div><section id="main-content" class="content"><div class="example-wrap"><pre class="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>
<span id="466">466</span>
<span id="467">467</span>
<span id="468">468</span>
<span id="469">469</span>
<span id="470">470</span>
<span id="471">471</span>
<span id="472">472</span>
<span id="473">473</span>
<span id="474">474</span>
<span id="475">475</span>
<span id="476">476</span>
<span id="477">477</span>
<span id="478">478</span>
<span id="479">479</span>
<span id="480">480</span>
<span id="481">481</span>
<span id="482">482</span>
<span id="483">483</span>
<span id="484">484</span>
<span id="485">485</span>
<span id="486">486</span>
<span id="487">487</span>
<span id="488">488</span>
<span id="489">489</span>
<span id="490">490</span>
<span id="491">491</span>
<span id="492">492</span>
<span id="493">493</span>
<span id="494">494</span>
<span id="495">495</span>
<span id="496">496</span>
<span id="497">497</span>
<span id="498">498</span>
<span id="499">499</span>
<span id="500">500</span>
<span id="501">501</span>
<span id="502">502</span>
<span id="503">503</span>
<span id="504">504</span>
<span id="505">505</span>
<span id="506">506</span>
<span id="507">507</span>
<span id="508">508</span>
<span id="509">509</span>
<span id="510">510</span>
<span id="511">511</span>
<span id="512">512</span>
<span id="513">513</span>
<span id="514">514</span>
<span id="515">515</span>
<span id="516">516</span>
<span id="517">517</span>
<span id="518">518</span>
<span id="519">519</span>
<span id="520">520</span>
<span id="521">521</span>
<span id="522">522</span>
<span id="523">523</span>
<span id="524">524</span>
<span id="525">525</span>
<span id="526">526</span>
<span id="527">527</span>
<span id="528">528</span>
<span id="529">529</span>
<span id="530">530</span>
<span id="531">531</span>
<span id="532">532</span>
<span id="533">533</span>
<span id="534">534</span>
<span id="535">535</span>
<span id="536">536</span>
<span id="537">537</span>
<span id="538">538</span>
<span id="539">539</span>
<span id="540">540</span>
<span id="541">541</span>
<span id="542">542</span>
<span id="543">543</span>
<span id="544">544</span>
<span id="545">545</span>
<span id="546">546</span>
<span id="547">547</span>
<span id="548">548</span>
<span id="549">549</span>
<span id="550">550</span>
<span id="551">551</span>
<span id="552">552</span>
<span id="553">553</span>
<span id="554">554</span>
<span id="555">555</span>
<span id="556">556</span>
<span id="557">557</span>
<span id="558">558</span>
<span id="559">559</span>
<span id="560">560</span>
<span id="561">561</span>
<span id="562">562</span>
<span id="563">563</span>
<span id="564">564</span>
<span id="565">565</span>
<span id="566">566</span>
<span id="567">567</span>
<span id="568">568</span>
<span id="569">569</span>
<span id="570">570</span>
<span id="571">571</span>
<span id="572">572</span>
<span id="573">573</span>
<span id="574">574</span>
<span id="575">575</span>
<span id="576">576</span>
<span id="577">577</span>
<span id="578">578</span>
<span id="579">579</span>
<span id="580">580</span>
<span id="581">581</span>
<span id="582">582</span>
<span id="583">583</span>
<span id="584">584</span>
<span id="585">585</span>
<span id="586">586</span>
<span id="587">587</span>
<span id="588">588</span>
<span id="589">589</span>
<span id="590">590</span>
<span id="591">591</span>
<span id="592">592</span>
<span id="593">593</span>
<span id="594">594</span>
<span id="595">595</span>
<span id="596">596</span>
<span id="597">597</span>
<span id="598">598</span>
<span id="599">599</span>
<span id="600">600</span>
<span id="601">601</span>
<span id="602">602</span>
<span id="603">603</span>
<span id="604">604</span>
<span id="605">605</span>
<span id="606">606</span>
<span id="607">607</span>
<span id="608">608</span>
<span id="609">609</span>
<span id="610">610</span>
<span id="611">611</span>
<span id="612">612</span>
<span id="613">613</span>
<span id="614">614</span>
<span id="615">615</span>
<span id="616">616</span>
<span id="617">617</span>
<span id="618">618</span>
<span id="619">619</span>
<span id="620">620</span>
<span id="621">621</span>
<span id="622">622</span>
<span id="623">623</span>
<span id="624">624</span>
<span id="625">625</span>
<span id="626">626</span>
<span id="627">627</span>
<span id="628">628</span>
<span id="629">629</span>
<span id="630">630</span>
<span id="631">631</span>
<span id="632">632</span>
<span id="633">633</span>
<span id="634">634</span>
<span id="635">635</span>
<span id="636">636</span>
<span id="637">637</span>
<span id="638">638</span>
<span id="639">639</span>
<span id="640">640</span>
<span id="641">641</span>
<span id="642">642</span>
<span id="643">643</span>
<span id="644">644</span>
<span id="645">645</span>
<span id="646">646</span>
<span id="647">647</span>
<span id="648">648</span>
<span id="649">649</span>
<span id="650">650</span>
<span id="651">651</span>
<span id="652">652</span>
<span id="653">653</span>
<span id="654">654</span>
<span id="655">655</span>
<span id="656">656</span>
<span id="657">657</span>
<span id="658">658</span>
<span id="659">659</span>
<span id="660">660</span>
<span id="661">661</span>
<span id="662">662</span>
<span id="663">663</span>
<span id="664">664</span>
<span id="665">665</span>
<span id="666">666</span>
<span id="667">667</span>
<span id="668">668</span>
<span id="669">669</span>
<span id="670">670</span>
<span id="671">671</span>
<span id="672">672</span>
<span id="673">673</span>
<span id="674">674</span>
<span id="675">675</span>
<span id="676">676</span>
<span id="677">677</span>
<span id="678">678</span>
<span id="679">679</span>
</pre><pre class="rust"><code><span class="doccomment">//! Session management for Actix Web.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! The HTTP protocol, at a first glance, is stateless: the client sends a request, the server</span>
<span class="doccomment">//! parses its content, performs some processing and returns a response. The outcome is only</span>
<span class="doccomment">//! influenced by the provided inputs (i.e. the request content) and whatever state the server</span>
<span class="doccomment">//! queries while performing its processing.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! Stateless systems are easier to reason about, but they are not quite as powerful as we need them</span>
<span class="doccomment">//! to be - e.g. how do you authenticate a user? The user would be forced to authenticate **for</span>
<span class="doccomment">//! every single request**. That is, for example, how &#39;Basic&#39; Authentication works. While it may</span>
<span class="doccomment">//! work for a machine user (i.e. an API client), it is impractical for a person—you do not want a</span>
<span class="doccomment">//! login prompt on every single page you navigate to!</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! There is a solution - **sessions**. Using sessions the server can attach state to a set of</span>
<span class="doccomment">//! requests coming from the same client. They are built on top of cookies - the server sets a</span>
<span class="doccomment">//! cookie in the HTTP response (`Set-Cookie` header), the client (e.g. the browser) will store the</span>
<span class="doccomment">//! cookie and play it back to the server when sending new requests (using the `Cookie` header).</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! We refer to the cookie used for sessions as a **session cookie**. Its content is called</span>
<span class="doccomment">//! **session key** (or **session ID**), while the state attached to the session is referred to as</span>
<span class="doccomment">//! **session state**.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! `actix-session` provides an easy-to-use framework to manage sessions in applications built on</span>
<span class="doccomment">//! top of Actix Web. [`SessionMiddleware`] is the middleware underpinning the functionality</span>
<span class="doccomment">//! provided by `actix-session`; it takes care of all the session cookie handling and instructs the</span>
<span class="doccomment">//! **storage backend** to create/delete/update the session state based on the operations performed</span>
<span class="doccomment">//! against the active [`Session`].</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! `actix-session` provides some built-in storage backends: ([`CookieSessionStore`],</span>
<span class="doccomment">//! [`RedisSessionStore`], and [`RedisActorSessionStore`]) - you can create a custom storage backend</span>
<span class="doccomment">//! by implementing the [`SessionStore`] trait.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! Further reading on sessions:</span>
<span class="doccomment">//! - [RFC6265](https://datatracker.ietf.org/doc/html/rfc6265);</span>
<span class="doccomment">//! - [OWASP&#39;s session management cheat-sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html).</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! # Getting started</span>
<span class="doccomment">//! To start using sessions in your Actix Web application you must register [`SessionMiddleware`]</span>
<span class="doccomment">//! as a middleware on your `App`:</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```no_run</span>
<span class="doccomment">//! use actix_web::{web, App, HttpServer, HttpResponse, Error};</span>
<span class="doccomment">//! use actix_session::{Session, SessionMiddleware, storage::RedisActorSessionStore};</span>
<span class="doccomment">//! use actix_web::cookie::Key;</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[actix_web::main]</span>
<span class="doccomment">//! async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">//! // The secret key would usually be read from a configuration file/environment variables.</span>
<span class="doccomment">//! let secret_key = Key::generate();</span>
<span class="doccomment">//! let redis_connection_string = &quot;127.0.0.1:6379&quot;;</span>
<span class="doccomment">//! HttpServer::new(move ||</span>
<span class="doccomment">//! App::new()</span>
<span class="doccomment">//! // Add session management to your application using Redis for session state storage</span>
<span class="doccomment">//! .wrap(</span>
<span class="doccomment">//! SessionMiddleware::new(</span>
<span class="doccomment">//! RedisActorSessionStore::new(redis_connection_string),</span>
<span class="doccomment">//! secret_key.clone()</span>
<span class="doccomment">//! )</span>
<span class="doccomment">//! )</span>
<span class="doccomment">//! .default_service(web::to(|| HttpResponse::Ok())))</span>
<span class="doccomment">//! .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">//! .run()</span>
<span class="doccomment">//! .await</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! The session state can be accessed and modified by your request handlers using the [`Session`]</span>
<span class="doccomment">//! extractor.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```no_run</span>
<span class="doccomment">//! use actix_web::Error;</span>
<span class="doccomment">//! use actix_session::Session;</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! fn index(session: Session) -&gt; Result&lt;&amp;&#39;static str, Error&gt; {</span>
<span class="doccomment">//! // access the session state</span>
<span class="doccomment">//! if let Some(count) = session.get::&lt;i32&gt;(&quot;counter&quot;)? {</span>
<span class="doccomment">//! println!(&quot;SESSION value: {}&quot;, count);</span>
<span class="doccomment">//! // modify the session state</span>
<span class="doccomment">//! session.insert(&quot;counter&quot;, count + 1)?;</span>
<span class="doccomment">//! } else {</span>
<span class="doccomment">//! session.insert(&quot;counter&quot;, 1)?;</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! Ok(&quot;Welcome!&quot;)</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! # Choosing A Backend</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! By default, `actix-session` does not provide any storage backend to retrieve and save the state</span>
<span class="doccomment">//! attached to your sessions. You can enable:</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! - a purely cookie-based &quot;backend&quot;, [`CookieSessionStore`], using the `cookie-session` feature</span>
<span class="doccomment">//! flag.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```toml</span>
<span class="doccomment">//! [dependencies]</span>
<span class="doccomment">//! # ...</span>
<span class="doccomment">//! actix-session = { version = &quot;...&quot;, features = [&quot;cookie-session&quot;] }</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! - a Redis-based backend via [`actix-redis`](https://docs.rs/acitx-redis),</span>
<span class="doccomment">//! [`RedisActorSessionStore`], using the `redis-actor-session` feature flag.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```toml</span>
<span class="doccomment">//! [dependencies]</span>
<span class="doccomment">//! # ...</span>
<span class="doccomment">//! actix-session = { version = &quot;...&quot;, features = [&quot;redis-actor-session&quot;] }</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! - a Redis-based backend via [`redis-rs`](https://docs.rs/redis-rs), [`RedisSessionStore`], using</span>
<span class="doccomment">//! the `redis-rs-session` feature flag.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```toml</span>
<span class="doccomment">//! [dependencies]</span>
<span class="doccomment">//! # ...</span>
<span class="doccomment">//! actix-session = { version = &quot;...&quot;, features = [&quot;redis-rs-session&quot;] }</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! Add the `redis-rs-tls-session` feature flag if you want to connect to Redis using a secured</span>
<span class="doccomment">//! connection:</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```toml</span>
<span class="doccomment">//! [dependencies]</span>
<span class="doccomment">//! # ...</span>
<span class="doccomment">//! actix-session = { version = &quot;...&quot;, features = [&quot;redis-rs-session&quot;, &quot;redis-rs-tls-session&quot;] }</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! You can implement your own session storage backend using the [`SessionStore`] trait.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! [`SessionStore`]: storage::SessionStore</span>
<span class="doccomment">//! [`CookieSessionStore`]: storage::CookieSessionStore</span>
<span class="doccomment">//! [`RedisSessionStore`]: storage::RedisSessionStore</span>
<span class="doccomment">//! [`RedisActorSessionStore`]: storage::RedisActorSessionStore</span>
<span class="attribute">#![<span class="ident">deny</span>(<span class="ident">rust_2018_idioms</span>, <span class="ident">nonstandard_style</span>)]</span>
<span class="attribute">#![<span class="ident">warn</span>(<span class="ident">future_incompatible</span>, <span class="ident">missing_docs</span>)]</span>
<span class="attribute">#![<span class="ident">doc</span>(<span class="ident">html_logo_url</span> <span class="op">=</span> <span class="string">&quot;https://actix.rs/img/logo.png&quot;</span>)]</span>
<span class="attribute">#![<span class="ident">doc</span>(<span class="ident">html_favicon_url</span> <span class="op">=</span> <span class="string">&quot;https://actix.rs/favicon.ico&quot;</span>)]</span>
<span class="attribute">#![<span class="ident">cfg_attr</span>(<span class="ident">docsrs</span>, <span class="ident">feature</span>(<span class="ident">doc_cfg</span>))]</span>
<span class="kw">mod</span> <span class="ident">middleware</span>;
<span class="kw">mod</span> <span class="ident">session</span>;
<span class="kw">mod</span> <span class="ident">session_ext</span>;
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">storage</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::middleware</span>::{
<span class="ident">CookieContentSecurity</span>, <span class="ident">SessionLength</span>, <span class="ident">SessionMiddleware</span>, <span class="ident">SessionMiddlewareBuilder</span>,
};
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::session</span>::{<span class="ident">Session</span>, <span class="ident">SessionStatus</span>};
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::session_ext::SessionExt</span>;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">test_helpers</span> {
<span class="kw">use</span> <span class="ident">actix_web::cookie::Key</span>;
<span class="kw">use</span> <span class="ident">rand</span>::{<span class="ident">distributions::Alphanumeric</span>, <span class="ident">thread_rng</span>, <span class="ident">Rng</span>};
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">storage::SessionStore</span>, <span class="ident">CookieContentSecurity</span>};
<span class="doccomment">/// Generate a random cookie signing/encryption key.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">key</span>() -&gt; <span class="ident">Key</span> {
<span class="kw">let</span> <span class="ident">signing_key</span>: <span class="ident">String</span> <span class="op">=</span> <span class="ident">thread_rng</span>()
.<span class="ident">sample_iter</span>(<span class="kw-2">&amp;</span><span class="ident">Alphanumeric</span>)
.<span class="ident">take</span>(<span class="number">64</span>)
.<span class="ident">map</span>(<span class="ident">char::from</span>)
.<span class="ident">collect</span>();
<span class="ident">Key::from</span>(<span class="ident">signing_key</span>.<span class="ident">as_bytes</span>())
}
<span class="doccomment">/// A ready-to-go acceptance test suite to verify that sessions behave as expected</span>
<span class="doccomment">/// regardless of the underlying session store.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// `is_invalidation_supported` must be set to `true` if the backend supports</span>
<span class="doccomment">/// &quot;remembering&quot; that a session has been invalidated (e.g. by logging out).</span>
<span class="doccomment">/// It should be to `false` if the backend allows multiple cookies to be active</span>
<span class="doccomment">/// at the same time (e.g. cookie store backend).</span>
<span class="kw">pub</span> <span class="kw">async</span> <span class="kw">fn</span> <span class="ident">acceptance_test_suite</span><span class="op">&lt;</span><span class="ident">F</span>, <span class="ident">Store</span><span class="op">&gt;</span>(<span class="ident">store_builder</span>: <span class="ident">F</span>, <span class="ident">is_invalidation_supported</span>: <span class="ident">bool</span>)
<span class="kw">where</span>
<span class="ident">Store</span>: <span class="ident">SessionStore</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">F</span>: <span class="ident">Fn</span>() -&gt; <span class="ident">Store</span> <span class="op">+</span> <span class="ident">Clone</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
{
<span class="kw">for</span> <span class="ident">policy</span> <span class="kw">in</span> <span class="kw-2">&amp;</span>[
<span class="ident">CookieContentSecurity::Signed</span>,
<span class="ident">CookieContentSecurity::Private</span>,
] {
<span class="macro">println!</span>(<span class="string">&quot;Using {:?} as cookie content security policy.&quot;</span>, <span class="ident">policy</span>);
<span class="ident">acceptance_tests::basic_workflow</span>(<span class="ident">store_builder</span>.<span class="ident">clone</span>(), <span class="kw-2">*</span><span class="ident">policy</span>).<span class="kw">await</span>;
<span class="ident">acceptance_tests::expiration_is_refreshed_on_changes</span>(<span class="ident">store_builder</span>.<span class="ident">clone</span>(), <span class="kw-2">*</span><span class="ident">policy</span>)
.<span class="kw">await</span>;
<span class="ident">acceptance_tests::complex_workflow</span>(
<span class="ident">store_builder</span>.<span class="ident">clone</span>(),
<span class="ident">is_invalidation_supported</span>,
<span class="kw-2">*</span><span class="ident">policy</span>,
)
.<span class="kw">await</span>;
<span class="ident">acceptance_tests::guard</span>(<span class="ident">store_builder</span>.<span class="ident">clone</span>(), <span class="kw-2">*</span><span class="ident">policy</span>).<span class="kw">await</span>;
}
}
<span class="kw">mod</span> <span class="ident">acceptance_tests</span> {
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">dev::Service</span>,
<span class="ident">guard</span>, <span class="ident">middleware</span>, <span class="ident">test</span>,
<span class="ident">web</span>::{<span class="self">self</span>, <span class="ident">get</span>, <span class="ident">post</span>, <span class="ident">resource</span>, <span class="ident">Bytes</span>},
<span class="ident">App</span>, <span class="ident">HttpResponse</span>, <span class="prelude-ty">Result</span>,
};
<span class="kw">use</span> <span class="ident">serde</span>::{<span class="ident">Deserialize</span>, <span class="ident">Serialize</span>};
<span class="kw">use</span> <span class="ident">serde_json::json</span>;
<span class="kw">use</span> <span class="ident">time::Duration</span>;
<span class="kw">use</span> <span class="kw">crate</span>::{
<span class="ident">middleware::SessionLength</span>, <span class="ident">storage::SessionStore</span>, <span class="ident">test_helpers::key</span>,
<span class="ident">CookieContentSecurity</span>, <span class="ident">Session</span>, <span class="ident">SessionExt</span>, <span class="ident">SessionMiddleware</span>,
};
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">async</span> <span class="kw">fn</span> <span class="ident">basic_workflow</span><span class="op">&lt;</span><span class="ident">F</span>, <span class="ident">Store</span><span class="op">&gt;</span>(
<span class="ident">store_builder</span>: <span class="ident">F</span>,
<span class="ident">policy</span>: <span class="ident">CookieContentSecurity</span>,
) <span class="kw">where</span>
<span class="ident">Store</span>: <span class="ident">SessionStore</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">F</span>: <span class="ident">Fn</span>() -&gt; <span class="ident">Store</span> <span class="op">+</span> <span class="ident">Clone</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
{
<span class="kw">let</span> <span class="ident">app</span> <span class="op">=</span> <span class="ident">test::init_service</span>(
<span class="ident">App::new</span>()
.<span class="ident">wrap</span>(
<span class="ident">SessionMiddleware::builder</span>(<span class="ident">store_builder</span>(), <span class="ident">key</span>())
.<span class="ident">cookie_path</span>(<span class="string">&quot;/test/&quot;</span>.<span class="ident">into</span>())
.<span class="ident">cookie_name</span>(<span class="string">&quot;actix-test&quot;</span>.<span class="ident">into</span>())
.<span class="ident">cookie_domain</span>(<span class="prelude-val">Some</span>(<span class="string">&quot;localhost&quot;</span>.<span class="ident">into</span>()))
.<span class="ident">cookie_content_security</span>(<span class="ident">policy</span>)
.<span class="ident">session_length</span>(<span class="ident">SessionLength::Predetermined</span> {
<span class="ident">max_session_length</span>: <span class="prelude-val">Some</span>(<span class="ident">time::Duration::seconds</span>(<span class="number">100</span>)),
})
.<span class="ident">build</span>(),
)
.<span class="ident">service</span>(<span class="ident">web::resource</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">to</span>(<span class="op">|</span><span class="ident">ses</span>: <span class="ident">Session</span><span class="op">|</span> <span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="ident">ses</span>.<span class="ident">insert</span>(<span class="string">&quot;counter&quot;</span>, <span class="number">100</span>);
<span class="string">&quot;test&quot;</span>
}))
.<span class="ident">service</span>(<span class="ident">web::resource</span>(<span class="string">&quot;/test/&quot;</span>).<span class="ident">to</span>(<span class="op">|</span><span class="ident">ses</span>: <span class="ident">Session</span><span class="op">|</span> <span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> <span class="ident">val</span>: <span class="ident">usize</span> <span class="op">=</span> <span class="ident">ses</span>.<span class="ident">get</span>(<span class="string">&quot;counter&quot;</span>).<span class="ident">unwrap</span>().<span class="ident">unwrap</span>();
<span class="macro">format!</span>(<span class="string">&quot;counter: {}&quot;</span>, <span class="ident">val</span>)
})),
)
.<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">request</span> <span class="op">=</span> <span class="ident">test::TestRequest::get</span>().<span class="ident">to_request</span>();
<span class="kw">let</span> <span class="ident">response</span> <span class="op">=</span> <span class="ident">app</span>.<span class="ident">call</span>(<span class="ident">request</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">cookie</span> <span class="op">=</span> <span class="ident">response</span>
.<span class="ident">response</span>()
.<span class="ident">cookies</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;actix-test&quot;</span>)
.<span class="ident">unwrap</span>()
.<span class="ident">clone</span>();
<span class="macro">assert_eq!</span>(<span class="ident">cookie</span>.<span class="ident">path</span>().<span class="ident">unwrap</span>(), <span class="string">&quot;/test/&quot;</span>);
<span class="kw">let</span> <span class="ident">request</span> <span class="op">=</span> <span class="ident">test::TestRequest::with_uri</span>(<span class="string">&quot;/test/&quot;</span>)
.<span class="ident">cookie</span>(<span class="ident">cookie</span>)
.<span class="ident">to_request</span>();
<span class="kw">let</span> <span class="ident">body</span> <span class="op">=</span> <span class="ident">test::call_and_read_body</span>(<span class="kw-2">&amp;</span><span class="ident">app</span>, <span class="ident">request</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(<span class="ident">body</span>, <span class="ident">Bytes::from_static</span>(<span class="string">b&quot;counter: 100&quot;</span>));
}
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">async</span> <span class="kw">fn</span> <span class="ident">expiration_is_refreshed_on_changes</span><span class="op">&lt;</span><span class="ident">F</span>, <span class="ident">Store</span><span class="op">&gt;</span>(
<span class="ident">store_builder</span>: <span class="ident">F</span>,
<span class="ident">policy</span>: <span class="ident">CookieContentSecurity</span>,
) <span class="kw">where</span>
<span class="ident">Store</span>: <span class="ident">SessionStore</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">F</span>: <span class="ident">Fn</span>() -&gt; <span class="ident">Store</span> <span class="op">+</span> <span class="ident">Clone</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
{
<span class="kw">let</span> <span class="ident">app</span> <span class="op">=</span> <span class="ident">test::init_service</span>(
<span class="ident">App::new</span>()
.<span class="ident">wrap</span>(
<span class="ident">SessionMiddleware::builder</span>(<span class="ident">store_builder</span>(), <span class="ident">key</span>())
.<span class="ident">cookie_content_security</span>(<span class="ident">policy</span>)
.<span class="ident">session_length</span>(<span class="ident">SessionLength::Predetermined</span> {
<span class="ident">max_session_length</span>: <span class="prelude-val">Some</span>(<span class="ident">time::Duration::seconds</span>(<span class="number">60</span>)),
})
.<span class="ident">build</span>(),
)
.<span class="ident">service</span>(<span class="ident">web::resource</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">to</span>(<span class="op">|</span><span class="ident">ses</span>: <span class="ident">Session</span><span class="op">|</span> <span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="ident">ses</span>.<span class="ident">insert</span>(<span class="string">&quot;counter&quot;</span>, <span class="number">100</span>);
<span class="string">&quot;test&quot;</span>
}))
.<span class="ident">service</span>(<span class="ident">web::resource</span>(<span class="string">&quot;/test/&quot;</span>).<span class="ident">to</span>(<span class="op">|</span><span class="op">|</span> <span class="kw">async</span> <span class="kw">move</span> { <span class="string">&quot;no-changes-in-session&quot;</span> })),
)
.<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">request</span> <span class="op">=</span> <span class="ident">test::TestRequest::get</span>().<span class="ident">to_request</span>();
<span class="kw">let</span> <span class="ident">response</span> <span class="op">=</span> <span class="ident">app</span>.<span class="ident">call</span>(<span class="ident">request</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">cookie_1</span> <span class="op">=</span> <span class="ident">response</span>
.<span class="ident">response</span>()
.<span class="ident">cookies</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;id&quot;</span>)
.<span class="ident">expect</span>(<span class="string">&quot;Cookie is set&quot;</span>);
<span class="macro">assert_eq!</span>(<span class="ident">cookie_1</span>.<span class="ident">max_age</span>(), <span class="prelude-val">Some</span>(<span class="ident">Duration::seconds</span>(<span class="number">60</span>)));
<span class="kw">let</span> <span class="ident">request</span> <span class="op">=</span> <span class="ident">test::TestRequest::with_uri</span>(<span class="string">&quot;/test/&quot;</span>).<span class="ident">to_request</span>();
<span class="kw">let</span> <span class="ident">response</span> <span class="op">=</span> <span class="ident">app</span>.<span class="ident">call</span>(<span class="ident">request</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert!</span>(<span class="ident">response</span>.<span class="ident">response</span>().<span class="ident">cookies</span>().<span class="ident">next</span>().<span class="ident">is_none</span>());
<span class="kw">let</span> <span class="ident">request</span> <span class="op">=</span> <span class="ident">test::TestRequest::get</span>().<span class="ident">to_request</span>();
<span class="kw">let</span> <span class="ident">response</span> <span class="op">=</span> <span class="ident">app</span>.<span class="ident">call</span>(<span class="ident">request</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">cookie_2</span> <span class="op">=</span> <span class="ident">response</span>
.<span class="ident">response</span>()
.<span class="ident">cookies</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;id&quot;</span>)
.<span class="ident">expect</span>(<span class="string">&quot;Cookie is set&quot;</span>);
<span class="macro">assert_eq!</span>(<span class="ident">cookie_2</span>.<span class="ident">max_age</span>(), <span class="prelude-val">Some</span>(<span class="ident">Duration::seconds</span>(<span class="number">60</span>)));
}
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">async</span> <span class="kw">fn</span> <span class="ident">guard</span><span class="op">&lt;</span><span class="ident">F</span>, <span class="ident">Store</span><span class="op">&gt;</span>(<span class="ident">store_builder</span>: <span class="ident">F</span>, <span class="ident">policy</span>: <span class="ident">CookieContentSecurity</span>)
<span class="kw">where</span>
<span class="ident">Store</span>: <span class="ident">SessionStore</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">F</span>: <span class="ident">Fn</span>() -&gt; <span class="ident">Store</span> <span class="op">+</span> <span class="ident">Clone</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
{
<span class="kw">let</span> <span class="ident">srv</span> <span class="op">=</span> <span class="ident">actix_test::start</span>(<span class="kw">move</span> <span class="op">|</span><span class="op">|</span> {
<span class="ident">App::new</span>()
.<span class="ident">wrap</span>(
<span class="ident">SessionMiddleware::builder</span>(<span class="ident">store_builder</span>(), <span class="ident">key</span>())
.<span class="ident">cookie_name</span>(<span class="string">&quot;test-session&quot;</span>.<span class="ident">into</span>())
.<span class="ident">cookie_content_security</span>(<span class="ident">policy</span>)
.<span class="ident">session_length</span>(<span class="ident">SessionLength::Predetermined</span> {
<span class="ident">max_session_length</span>: <span class="prelude-val">Some</span>(<span class="ident">time::Duration::days</span>(<span class="number">7</span>)),
})
.<span class="ident">build</span>(),
)
.<span class="ident">wrap</span>(<span class="ident">middleware::Logger::default</span>())
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">route</span>(<span class="ident">get</span>().<span class="ident">to</span>(<span class="ident">index</span>)))
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/do_something&quot;</span>).<span class="ident">route</span>(<span class="ident">post</span>().<span class="ident">to</span>(<span class="ident">do_something</span>)))
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/login&quot;</span>).<span class="ident">route</span>(<span class="ident">post</span>().<span class="ident">to</span>(<span class="ident">login</span>)))
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/logout&quot;</span>).<span class="ident">route</span>(<span class="ident">post</span>().<span class="ident">to</span>(<span class="ident">logout</span>)))
.<span class="ident">service</span>(
<span class="ident">web::scope</span>(<span class="string">&quot;/protected&quot;</span>)
.<span class="ident">guard</span>(<span class="ident">guard::fn_guard</span>(<span class="op">|</span><span class="ident">g</span><span class="op">|</span> {
<span class="ident">g</span>.<span class="ident">get_session</span>().<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>(<span class="string">&quot;user_id&quot;</span>).<span class="ident">unwrap</span>().<span class="ident">is_some</span>()
}))
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/count&quot;</span>).<span class="ident">route</span>(<span class="ident">get</span>().<span class="ident">to</span>(<span class="ident">count</span>))),
)
});
<span class="comment">// Step 1: GET without session info</span>
<span class="comment">// - response should be a unsuccessful status</span>
<span class="kw">let</span> <span class="ident">req_1</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">get</span>(<span class="string">&quot;/protected/count&quot;</span>).<span class="ident">send</span>();
<span class="kw">let</span> <span class="ident">resp_1</span> <span class="op">=</span> <span class="ident">req_1</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert!</span>(<span class="op">!</span><span class="ident">resp_1</span>.<span class="ident">status</span>().<span class="ident">is_success</span>());
<span class="comment">// Step 2: POST to login</span>
<span class="comment">// - set-cookie actix-session will be in response (session cookie #1)</span>
<span class="comment">// - updates session state: {&quot;counter&quot;: 0, &quot;user_id&quot;: &quot;ferris&quot;}</span>
<span class="kw">let</span> <span class="ident">req_2</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">post</span>(<span class="string">&quot;/login&quot;</span>).<span class="ident">send_json</span>(<span class="kw-2">&amp;</span><span class="macro">json!</span>({<span class="string">&quot;user_id&quot;</span>: <span class="string">&quot;ferris&quot;</span>}));
<span class="kw">let</span> <span class="ident">resp_2</span> <span class="op">=</span> <span class="ident">req_2</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">cookie_1</span> <span class="op">=</span> <span class="ident">resp_2</span>
.<span class="ident">cookies</span>()
.<span class="ident">unwrap</span>()
.<span class="ident">clone</span>()
.<span class="ident">into_iter</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;test-session&quot;</span>)
.<span class="ident">unwrap</span>();
<span class="comment">// Step 3: POST to do_something</span>
<span class="comment">// - adds new session state: {&quot;counter&quot;: 1, &quot;user_id&quot;: &quot;ferris&quot; }</span>
<span class="comment">// - set-cookie actix-session should be in response (session cookie #2)</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 1, &quot;user_id&quot;: None}</span>
<span class="kw">let</span> <span class="ident">req_3</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">post</span>(<span class="string">&quot;/do_something&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_1</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_3</span> <span class="op">=</span> <span class="ident">req_3</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">result_3</span> <span class="op">=</span> <span class="ident">resp_3</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_3</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">Some</span>(<span class="string">&quot;ferris&quot;</span>.<span class="ident">into</span>()),
<span class="ident">counter</span>: <span class="number">1</span>
}
);
<span class="kw">let</span> <span class="ident">cookie_2</span> <span class="op">=</span> <span class="ident">resp_3</span>
.<span class="ident">cookies</span>()
.<span class="ident">unwrap</span>()
.<span class="ident">clone</span>()
.<span class="ident">into_iter</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;test-session&quot;</span>)
.<span class="ident">unwrap</span>();
<span class="comment">// Step 4: GET using a existing user id</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 3, &quot;user_id&quot;: &quot;ferris&quot;}</span>
<span class="kw">let</span> <span class="ident">req_4</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">get</span>(<span class="string">&quot;/protected/count&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_2</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_4</span> <span class="op">=</span> <span class="ident">req_4</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">result_4</span> <span class="op">=</span> <span class="ident">resp_4</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_4</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">Some</span>(<span class="string">&quot;ferris&quot;</span>.<span class="ident">into</span>()),
<span class="ident">counter</span>: <span class="number">1</span>
}
);
}
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">async</span> <span class="kw">fn</span> <span class="ident">complex_workflow</span><span class="op">&lt;</span><span class="ident">F</span>, <span class="ident">Store</span><span class="op">&gt;</span>(
<span class="ident">store_builder</span>: <span class="ident">F</span>,
<span class="ident">is_invalidation_supported</span>: <span class="ident">bool</span>,
<span class="ident">policy</span>: <span class="ident">CookieContentSecurity</span>,
) <span class="kw">where</span>
<span class="ident">Store</span>: <span class="ident">SessionStore</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">F</span>: <span class="ident">Fn</span>() -&gt; <span class="ident">Store</span> <span class="op">+</span> <span class="ident">Clone</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
{
<span class="kw">let</span> <span class="ident">srv</span> <span class="op">=</span> <span class="ident">actix_test::start</span>(<span class="kw">move</span> <span class="op">|</span><span class="op">|</span> {
<span class="ident">App::new</span>()
.<span class="ident">wrap</span>(
<span class="ident">SessionMiddleware::builder</span>(<span class="ident">store_builder</span>(), <span class="ident">key</span>())
.<span class="ident">cookie_name</span>(<span class="string">&quot;test-session&quot;</span>.<span class="ident">into</span>())
.<span class="ident">cookie_content_security</span>(<span class="ident">policy</span>)
.<span class="ident">session_length</span>(<span class="ident">SessionLength::Predetermined</span> {
<span class="ident">max_session_length</span>: <span class="prelude-val">Some</span>(<span class="ident">time::Duration::days</span>(<span class="number">7</span>)),
})
.<span class="ident">build</span>(),
)
.<span class="ident">wrap</span>(<span class="ident">middleware::Logger::default</span>())
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">route</span>(<span class="ident">get</span>().<span class="ident">to</span>(<span class="ident">index</span>)))
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/do_something&quot;</span>).<span class="ident">route</span>(<span class="ident">post</span>().<span class="ident">to</span>(<span class="ident">do_something</span>)))
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/login&quot;</span>).<span class="ident">route</span>(<span class="ident">post</span>().<span class="ident">to</span>(<span class="ident">login</span>)))
.<span class="ident">service</span>(<span class="ident">resource</span>(<span class="string">&quot;/logout&quot;</span>).<span class="ident">route</span>(<span class="ident">post</span>().<span class="ident">to</span>(<span class="ident">logout</span>)))
});
<span class="comment">// Step 1: GET index</span>
<span class="comment">// - set-cookie actix-session should NOT be in response (session data is empty)</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 0, &quot;user_id&quot;: None}</span>
<span class="kw">let</span> <span class="ident">req_1a</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">get</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_1</span> <span class="op">=</span> <span class="ident">req_1a</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert!</span>(<span class="ident">resp_1</span>.<span class="ident">cookies</span>().<span class="ident">unwrap</span>().<span class="ident">is_empty</span>());
<span class="kw">let</span> <span class="ident">result_1</span> <span class="op">=</span> <span class="ident">resp_1</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_1</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">None</span>,
<span class="ident">counter</span>: <span class="number">0</span>
}
);
<span class="comment">// Step 2: POST to do_something</span>
<span class="comment">// - adds new session state in redis: {&quot;counter&quot;: 1}</span>
<span class="comment">// - set-cookie actix-session should be in response (session cookie #1)</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 1, &quot;user_id&quot;: None}</span>
<span class="kw">let</span> <span class="ident">req_2</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">post</span>(<span class="string">&quot;/do_something&quot;</span>).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_2</span> <span class="op">=</span> <span class="ident">req_2</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">result_2</span> <span class="op">=</span> <span class="ident">resp_2</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_2</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">None</span>,
<span class="ident">counter</span>: <span class="number">1</span>
}
);
<span class="kw">let</span> <span class="ident">cookie_1</span> <span class="op">=</span> <span class="ident">resp_2</span>
.<span class="ident">cookies</span>()
.<span class="ident">unwrap</span>()
.<span class="ident">clone</span>()
.<span class="ident">into_iter</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;test-session&quot;</span>)
.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">cookie_1</span>.<span class="ident">max_age</span>(), <span class="prelude-val">Some</span>(<span class="ident">Duration::days</span>(<span class="number">7</span>)));
<span class="comment">// Step 3: GET index, including session cookie #1 in request</span>
<span class="comment">// - set-cookie will *not* be in response</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 1, &quot;user_id&quot;: None}</span>
<span class="kw">let</span> <span class="ident">req_3</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">get</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_1</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_3</span> <span class="op">=</span> <span class="ident">req_3</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert!</span>(<span class="ident">resp_3</span>.<span class="ident">cookies</span>().<span class="ident">unwrap</span>().<span class="ident">is_empty</span>());
<span class="kw">let</span> <span class="ident">result_3</span> <span class="op">=</span> <span class="ident">resp_3</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_3</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">None</span>,
<span class="ident">counter</span>: <span class="number">1</span>
}
);
<span class="comment">// Step 4: POST again to do_something, including session cookie #1 in request</span>
<span class="comment">// - set-cookie will be in response (session cookie #2)</span>
<span class="comment">// - updates session state: {&quot;counter&quot;: 2}</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 2, &quot;user_id&quot;: None}</span>
<span class="kw">let</span> <span class="ident">req_4</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">post</span>(<span class="string">&quot;/do_something&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_1</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_4</span> <span class="op">=</span> <span class="ident">req_4</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">result_4</span> <span class="op">=</span> <span class="ident">resp_4</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_4</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">None</span>,
<span class="ident">counter</span>: <span class="number">2</span>
}
);
<span class="kw">let</span> <span class="ident">cookie_2</span> <span class="op">=</span> <span class="ident">resp_4</span>
.<span class="ident">cookies</span>()
.<span class="ident">unwrap</span>()
.<span class="ident">clone</span>()
.<span class="ident">into_iter</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;test-session&quot;</span>)
.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">cookie_2</span>.<span class="ident">max_age</span>(), <span class="prelude-val">Some</span>(<span class="ident">Duration::days</span>(<span class="number">7</span>)));
<span class="comment">// Step 5: POST to login, including session cookie #2 in request</span>
<span class="comment">// - set-cookie actix-session will be in response (session cookie #3)</span>
<span class="comment">// - updates session state: {&quot;counter&quot;: 2, &quot;user_id&quot;: &quot;ferris&quot;}</span>
<span class="kw">let</span> <span class="ident">req_5</span> <span class="op">=</span> <span class="ident">srv</span>
.<span class="ident">post</span>(<span class="string">&quot;/login&quot;</span>)
.<span class="ident">cookie</span>(<span class="ident">cookie_2</span>.<span class="ident">clone</span>())
.<span class="ident">send_json</span>(<span class="kw-2">&amp;</span><span class="macro">json!</span>({<span class="string">&quot;user_id&quot;</span>: <span class="string">&quot;ferris&quot;</span>}));
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_5</span> <span class="op">=</span> <span class="ident">req_5</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">cookie_3</span> <span class="op">=</span> <span class="ident">resp_5</span>
.<span class="ident">cookies</span>()
.<span class="ident">unwrap</span>()
.<span class="ident">clone</span>()
.<span class="ident">into_iter</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;test-session&quot;</span>)
.<span class="ident">unwrap</span>();
<span class="macro">assert_ne!</span>(<span class="ident">cookie_2</span>.<span class="ident">value</span>(), <span class="ident">cookie_3</span>.<span class="ident">value</span>());
<span class="kw">let</span> <span class="ident">result_5</span> <span class="op">=</span> <span class="ident">resp_5</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_5</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">Some</span>(<span class="string">&quot;ferris&quot;</span>.<span class="ident">into</span>()),
<span class="ident">counter</span>: <span class="number">2</span>
}
);
<span class="comment">// Step 6: GET index, including session cookie #3 in request</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 2, &quot;user_id&quot;: &quot;ferris&quot;}</span>
<span class="kw">let</span> <span class="ident">req_6</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">get</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_3</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_6</span> <span class="op">=</span> <span class="ident">req_6</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">result_6</span> <span class="op">=</span> <span class="ident">resp_6</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_6</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">Some</span>(<span class="string">&quot;ferris&quot;</span>.<span class="ident">into</span>()),
<span class="ident">counter</span>: <span class="number">2</span>
}
);
<span class="comment">// Step 7: POST again to do_something, including session cookie #3 in request</span>
<span class="comment">// - updates session state: {&quot;counter&quot;: 3, &quot;user_id&quot;: &quot;ferris&quot;}</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 3, &quot;user_id&quot;: &quot;ferris&quot;}</span>
<span class="kw">let</span> <span class="ident">req_7</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">post</span>(<span class="string">&quot;/do_something&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_3</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_7</span> <span class="op">=</span> <span class="ident">req_7</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">result_7</span> <span class="op">=</span> <span class="ident">resp_7</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_7</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">Some</span>(<span class="string">&quot;ferris&quot;</span>.<span class="ident">into</span>()),
<span class="ident">counter</span>: <span class="number">3</span>
}
);
<span class="comment">// Step 8: GET index, including session cookie #2 in request</span>
<span class="comment">// If invalidation is supported, no state will be found associated to this session.</span>
<span class="comment">// If invalidation is not supported, the old state will still be retrieved.</span>
<span class="kw">let</span> <span class="ident">req_8</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">get</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_2</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_8</span> <span class="op">=</span> <span class="ident">req_8</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">if</span> <span class="ident">is_invalidation_supported</span> {
<span class="macro">assert!</span>(<span class="ident">resp_8</span>.<span class="ident">cookies</span>().<span class="ident">unwrap</span>().<span class="ident">is_empty</span>());
<span class="kw">let</span> <span class="ident">result_8</span> <span class="op">=</span> <span class="ident">resp_8</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_8</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">None</span>,
<span class="ident">counter</span>: <span class="number">0</span>
}
);
} <span class="kw">else</span> {
<span class="kw">let</span> <span class="ident">result_8</span> <span class="op">=</span> <span class="ident">resp_8</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_8</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">None</span>,
<span class="ident">counter</span>: <span class="number">2</span>
}
);
}
<span class="comment">// Step 9: POST to logout, including session cookie #3</span>
<span class="comment">// - set-cookie actix-session will be in response with session cookie #3</span>
<span class="comment">// invalidation logic</span>
<span class="kw">let</span> <span class="ident">req_9</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">post</span>(<span class="string">&quot;/logout&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_3</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="ident">resp_9</span> <span class="op">=</span> <span class="ident">req_9</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">cookie_3</span> <span class="op">=</span> <span class="ident">resp_9</span>
.<span class="ident">cookies</span>()
.<span class="ident">unwrap</span>()
.<span class="ident">clone</span>()
.<span class="ident">into_iter</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="string">&quot;test-session&quot;</span>)
.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="number">0</span>, <span class="ident">cookie_3</span>.<span class="ident">max_age</span>().<span class="ident">map</span>(<span class="op">|</span><span class="ident">t</span><span class="op">|</span> <span class="ident">t</span>.<span class="ident">whole_seconds</span>()).<span class="ident">unwrap</span>());
<span class="macro">assert_eq!</span>(<span class="string">&quot;/&quot;</span>, <span class="ident">cookie_3</span>.<span class="ident">path</span>().<span class="ident">unwrap</span>());
<span class="comment">// Step 10: GET index, including session cookie #3 in request</span>
<span class="comment">// - set-cookie actix-session should NOT be in response if invalidation is supported</span>
<span class="comment">// - response should be: {&quot;counter&quot;: 0, &quot;user_id&quot;: None}</span>
<span class="kw">let</span> <span class="ident">req_10</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">get</span>(<span class="string">&quot;/&quot;</span>).<span class="ident">cookie</span>(<span class="ident">cookie_3</span>.<span class="ident">clone</span>()).<span class="ident">send</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">resp_10</span> <span class="op">=</span> <span class="ident">req_10</span>.<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">if</span> <span class="ident">is_invalidation_supported</span> {
<span class="macro">assert!</span>(<span class="ident">resp_10</span>.<span class="ident">cookies</span>().<span class="ident">unwrap</span>().<span class="ident">is_empty</span>());
}
<span class="kw">let</span> <span class="ident">result_10</span> <span class="op">=</span> <span class="ident">resp_10</span>.<span class="ident">json</span>::<span class="op">&lt;</span><span class="ident">IndexResponse</span><span class="op">&gt;</span>().<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(
<span class="ident">result_10</span>,
<span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">None</span>,
<span class="ident">counter</span>: <span class="number">0</span>
}
);
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Serialize</span>, <span class="ident">Deserialize</span>, <span class="ident">Debug</span>, <span class="ident">PartialEq</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">counter</span>: <span class="ident">i32</span>,
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">index</span>(<span class="ident">session</span>: <span class="ident">Session</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HttpResponse</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">user_id</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">session</span>.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>(<span class="string">&quot;user_id&quot;</span>).<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">counter</span>: <span class="ident">i32</span> <span class="op">=</span> <span class="ident">session</span>
.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">i32</span><span class="op">&gt;</span>(<span class="string">&quot;counter&quot;</span>)
.<span class="ident">unwrap_or</span>(<span class="prelude-val">Some</span>(<span class="number">0</span>))
.<span class="ident">unwrap_or</span>(<span class="number">0</span>);
<span class="prelude-val">Ok</span>(<span class="ident">HttpResponse::Ok</span>().<span class="ident">json</span>(<span class="kw-2">&amp;</span><span class="ident">IndexResponse</span> { <span class="ident">user_id</span>, <span class="ident">counter</span> }))
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">do_something</span>(<span class="ident">session</span>: <span class="ident">Session</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HttpResponse</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">user_id</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">session</span>.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>(<span class="string">&quot;user_id&quot;</span>).<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">counter</span>: <span class="ident">i32</span> <span class="op">=</span> <span class="ident">session</span>
.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">i32</span><span class="op">&gt;</span>(<span class="string">&quot;counter&quot;</span>)
.<span class="ident">unwrap_or</span>(<span class="prelude-val">Some</span>(<span class="number">0</span>))
.<span class="ident">map_or</span>(<span class="number">1</span>, <span class="op">|</span><span class="ident">inner</span><span class="op">|</span> <span class="ident">inner</span> <span class="op">+</span> <span class="number">1</span>);
<span class="ident">session</span>.<span class="ident">insert</span>(<span class="string">&quot;counter&quot;</span>, <span class="kw-2">&amp;</span><span class="ident">counter</span>)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="ident">HttpResponse::Ok</span>().<span class="ident">json</span>(<span class="kw-2">&amp;</span><span class="ident">IndexResponse</span> { <span class="ident">user_id</span>, <span class="ident">counter</span> }))
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">count</span>(<span class="ident">session</span>: <span class="ident">Session</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HttpResponse</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">user_id</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">session</span>.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>(<span class="string">&quot;user_id&quot;</span>).<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">counter</span>: <span class="ident">i32</span> <span class="op">=</span> <span class="ident">session</span>.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">i32</span><span class="op">&gt;</span>(<span class="string">&quot;counter&quot;</span>).<span class="ident">unwrap</span>().<span class="ident">unwrap</span>();
<span class="prelude-val">Ok</span>(<span class="ident">HttpResponse::Ok</span>().<span class="ident">json</span>(<span class="kw-2">&amp;</span><span class="ident">IndexResponse</span> { <span class="ident">user_id</span>, <span class="ident">counter</span> }))
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Deserialize</span>)]</span>
<span class="kw">struct</span> <span class="ident">Identity</span> {
<span class="ident">user_id</span>: <span class="ident">String</span>,
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">login</span>(<span class="ident">user_id</span>: <span class="ident">web::Json</span><span class="op">&lt;</span><span class="ident">Identity</span><span class="op">&gt;</span>, <span class="ident">session</span>: <span class="ident">Session</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HttpResponse</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">id</span> <span class="op">=</span> <span class="ident">user_id</span>.<span class="ident">into_inner</span>().<span class="ident">user_id</span>;
<span class="ident">session</span>.<span class="ident">insert</span>(<span class="string">&quot;user_id&quot;</span>, <span class="kw-2">&amp;</span><span class="ident">id</span>)<span class="question-mark">?</span>;
<span class="ident">session</span>.<span class="ident">renew</span>();
<span class="kw">let</span> <span class="ident">counter</span>: <span class="ident">i32</span> <span class="op">=</span> <span class="ident">session</span>
.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">i32</span><span class="op">&gt;</span>(<span class="string">&quot;counter&quot;</span>)
.<span class="ident">unwrap_or</span>(<span class="prelude-val">Some</span>(<span class="number">0</span>))
.<span class="ident">unwrap_or</span>(<span class="number">0</span>);
<span class="prelude-val">Ok</span>(<span class="ident">HttpResponse::Ok</span>().<span class="ident">json</span>(<span class="kw-2">&amp;</span><span class="ident">IndexResponse</span> {
<span class="ident">user_id</span>: <span class="prelude-val">Some</span>(<span class="ident">id</span>),
<span class="ident">counter</span>,
}))
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">logout</span>(<span class="ident">session</span>: <span class="ident">Session</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HttpResponse</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">id</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">session</span>.<span class="ident">get</span>(<span class="string">&quot;user_id&quot;</span>)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">body</span> <span class="op">=</span> <span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">x</span>) <span class="op">=</span> <span class="ident">id</span> {
<span class="ident">session</span>.<span class="ident">purge</span>();
<span class="macro">format!</span>(<span class="string">&quot;Logged out: {}&quot;</span>, <span class="ident">x</span>)
} <span class="kw">else</span> {
<span class="string">&quot;Could not log out anonymous user&quot;</span>.<span class="ident">to_owned</span>()
};
<span class="prelude-val">Ok</span>(<span class="ident">HttpResponse::Ok</span>().<span class="ident">body</span>(<span class="ident">body</span>))
}
}
}
</code></pre></div>
</section><section id="search" class="content hidden"></section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.61.0-nightly (63b8f01bb 2022-03-24)" ></div>
</body></html>