今日會展示在 Blazor 中,介紹如何儲存 Token 和存放的幾種位置以及他們的優缺點,還有帶著 Token 發送API
Token 怎麼儲存#
拿到 Token 後,應該放哪裡呢 ?
在前端可以存放資料的地方不多,主要有三個地方 記憶體、Cookie、localStorage
記憶體#
在拿到伺服器回傳的 Token 後就是在記憶體內,Token 是一種憑證理論上他應該受到保護,用完即丟不要存在任何的地方,這樣安全性是最高的,可是實際上如果一個網頁,不斷地要求使用者進行登入,應該很快就會被罵翻了,所以儲存在其他的方的需求產生了,只要 Token 的效期還沒有到就可以對後端資源做存取
Cookie#
- 可以設定效期
- 使用 HttpOnly 和 Secure Cookie,可以防止 Javascript 存取
- 如果 Token 太大可能會沒辦法放進 Cookie 內
- 需注意 CSRF 攻擊
localStorage#
- 使用上方便
- 較容易被 XSS 攻擊
完善登入流程#
1. 登入頁面處理#
看到昨天建立的 Login.razor
,注入 JS Runtime
登入後取得 Token ,再將 Token 儲存到 localStorage 中
1
2
3
4
5
6
| private async Task HandleValidSubmit()
{
var token = await(await Http.PostAsJsonAsync("api/Authorize/Login", loginDto)).Content.ReadAsStringAsync();
// 將 Token 寫入 localStorage
await Js.InvokeVoidAsync("localStorage.setItem", "token", $"{token}").ConfigureAwait(false);
}
|
2. 將登入按鈕放到右上角#
到 MainLayout.razor
內,將 About 取代成登入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| @inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="login">登入</a>
</div>
<article class="content px-4">
@Body
</article>
</main>
</div>
|
3. 為 Server 專案的 API 加入 Authorize#
我們將範例的 WeatherForecast
內的 Get
修改成需要身份驗證
1
2
3
4
5
6
7
8
9
10
11
12
| [HttpGet]
[Authorize]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
|
4. 處理 Client 專案 FetchData.razor
#
我們在 WeatherForecast
內的 API 加上 Authorize
直接呼叫就會是 401 未授權,所以需要再發出 API Request時帶上 Token
在最上面加入需要用到的服務
1
2
| @inject IJSRuntime Js
@inject NavigationManager NavigationManager
|
寫一個方法讀取 Token
1
2
3
4
5
6
| private string Token = string.Empty;
private async Task GetToken()
{
Token = await Js.InvokeAsync<string>("localStorage.getItem", "user").ConfigureAwait(false);
}
|
修改原本的取資料的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| protected override async Task OnInitializedAsync()
{
await GetToken();
if (string.IsNullOrWhiteSpace(Token))
{
NavigationManager.NavigateTo($"/login", false);
return;
}
var requestMsg = new HttpRequestMessage(HttpMethod.Get, $"/api/weatherforecast/{DateTime.Now.ToString("yyyy-MM-dd")}");
requestMsg.Headers.Add("Authorization", $"Bearer {Token}");
var response = await Http.SendAsync(requestMsg);
if (response.IsSuccessStatusCode)
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
}
}
|
若沒有 Token 會將使用者導向登入頁面
在這一個章節我們完成了基本的權限驗證,如果沒有登入的狀態下點選,FatchData 頁面會直接導向登入頁,待拿到 Token 後才可以進入頁面並且撈取資料,有人可能會有疑惑為什麼 Token 沒有在 Client 專案中驗證呢? 這是一個非常重要的知識點
在 Blazor WebAssembly 應用程式中,授權檢查是可以被略過的,因為使用者可以修改所有的用戶端程式碼。 這同樣也適用於所有的用戶端應用程式技術,包括 JavaScript SPA 架構或任何作業系統的原生應用程式。
前端是不安全的,不可以相信前端,在 Blaozr WebAssembly 你可以做頁面的導向,沒有登入時跳轉到登入頁,可以設定哪些權限可以看到哪些頁面,但是這些在前端都是可以被修改的,真正的驗證應該在後端,就算前端使用者用了一些方法抵達權限不足的頁面,他在提取資料時也後端也不可以放行
下個章節預計會介紹頁面導向與路由