【Web API 05-1】Basic Authentication
主題: |
【Web API 05-1】Basic Authentication |
文章簡介: |
說明如何透過一些手段,來增強 Web API 的安全性。 |
作者: |
江崑成(Vito) |
版本/產出日期: |
V1.0/2016.12.23 |
1. 前言
在前面的文章,我們已經說明了如何建立 Web API,並透過 IoC 來降低物件之間的耦合,接下來將會說明如何透過一些手段,來增強 Web API 的安全性。
先假設一下情境:
2. 每個帳號驗證完成後,會取得一個可以識別該帳號的 Token。
3. 同一個帳號一次只能登入一個裝置。
4. 若在登入 A 裝置後,取得 A 的 Token,那麼在登入 B 之後,會重新取得 B 的 Token,此時 A 的 Token 將不可使用。
3. Token 過期後,需要重新進行驗證並取得一組新的 Token。
驗證流程如下:
1. Basic Authentication:先透過帳號密碼來進行驗證,並產生 Token 回傳給 Client。
2. Client 進行後續呼叫 API 時,需將 Token 一併傳回 Server。
2. Token Authentication:每次呼叫 Web API 時,Server 會針對 Token 進行驗證並取得相關的授權資料(含角色)。
2. 資料庫準備
在之前的資料庫新增以下二個資料表:
3. Entities Project
Step 1. 開啟 WebApiDb.edmx 並更新資料庫模型。
Step 2. 整合 URF。
因為有更新資料庫模型,所以之前修改過的 Context.cs 及 Product.cs 也都會重新建立,所以我們必須再一次重新修改,為何需要修改,在 #4-1 的內容已經有說明,這邊就不再綴述。
4. Interface Project
新增 IUserService.cs,程式碼內容如下:
using System.Collections.Generic;
using Service.Pattern;
using WebApiDb.Entities;
namespace WebApiDb.Interface
{
public interface IUserService : IService<User>
{
bool Authenticate(string account, string password);
}
}
5. Service Project
新增 UserService.cs,程式碼內容如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Repository.Pattern.Repositories;
using Service.Pattern;
using WebApiDb.Entities;
using WebApiDb.Interface;
namespace WebApiDb.Service
{
public class UserService : Service<User>, IUserService
{
private readonly IRepositoryAsync<User> repository;
public UserService(IRepositoryAsync<User> repository)
: base(repository)
{
this.repository = repository;
}
public async Task<User> Authenticate(string account, string password)
{
var result = await
this.Query(o => o.Account == account && o.Password == password).SelectAsync();
return result.SingleOrDefault();
}
}
}
6. AuthController
新增 AuthController.cs,程式碼內容如下:
using Repository.Pattern.Infrastructure;
using Repository.Pattern.UnitOfWork;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using WebApiDb.Entities;
using WebApiDb.Interface;
namespace Hello.WebAPI.Controllers
{
public class AuthController : ApiController
{
private readonly IUnitOfWorkAsync unitOfWorkAsync;
private readonly IUserService userService;
public AuthController(
IUnitOfWorkAsync unitOfWorkAsync,
IUserService userService)
{
this.unitOfWorkAsync = unitOfWorkAsync;
this.userService = userService;
}
public async Task<IHttpActionResult> Authenticate(User user)
{
var result = await this.userService.Authenticate(user.Account, user.Password);
if (result != null)
{
return Ok(result);
}
return Unauthorized();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
this.unitOfWorkAsync.Dispose();
}
base.Dispose(disposing);
}
}
}
這邊的帳號密碼為示意用,一般密碼在傳輸時都會再經過加密,才可確保資料的安全。
另外,資料回傳的部分,一般也會視情況將資料處理後再進行回傳,而非如同本文章一樣直接進行回傳。
7. Action Route
Web API 2 預設是使用 HTTP 動詞來進行路由,但因為我們開發的並非全部都是符合 Restful 風格的網路資源,所以我們要將 Action 也加入路由中,讓非 Resuful 的資源可以透過 Action 的名稱路由來取得資源。
修改 WebApiConfig.cs 的程式碼,加入 Action 的名稱路由後如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace Hello.WebAPI
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApiWithAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
8. Test Web API
Post api/auth/Authenticate
Request:
Response:
這邊僅先測試 Web API 是否可正常呼叫及驗證,實際上資料並不會這樣直接回傳,更不可能包含 Password。
情境上也是通過驗證後,會回傳 Token 相關的資料,接下來會在下一個章節 #5-2 進行說明。
9. 參考來源
文章內容的敘述如有錯誤及觀念不正確,請不吝嗇指教,如有侵權內容也請您與我反應。感謝您~