WebAPI

【Web API 05-1】Basic Authentication

江崑成 2016/12/23 14:02:39
1800







主題

Web API 05-1Basic 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. 參考來源

文章內容的敘述如有錯誤及觀念不正確,請不吝嗇指教,如有侵權內容也請您與我反應。感謝您~

江崑成