Google Code Prettify

[Web API]從零開始建立基於 Token 的 ASP.NET Web API 2 身份驗證機制 (Visual Studio 2017)

經由這個範例為基礎,您可以建立一套自己的 ASP.NET Web API 2 身份驗證機制,本範例是以 Visual Studio 2017 製作且在本文的後半部有詳細的資料測試畫面,但畢竟只是個範例,完整性會較不足,如密碼加密處理就不在本文中介紹。


1. 建立專案 ( TokenAuthorizationExample.csproj)

    新增專案時選擇 ASP.NET Web 應用程式


    選擇 Web API


    專案建立後系統會生成下圖的內容




2.啟用 SSL

點選 [方案總管] 中的專案名稱 (TokenAuthorizationExample),然後在屬性視窗中啟用 SSL。




點選 [方案總管] 中的專案名稱 (TokenAuthorizationExample)上點擊滑鼠右鍵,然後選擇內容,在 Web 頁籤將 URL 設定為屬性中 SSL URL 屬性中的值 ,並點選 [建立虛擬目錄]。




3.加套件


在套件管理器主控台執行以下指令藉以安裝必須的套件:

  Install-Package Microsoft.Owin.Host.SystemWeb -projectname TokenAuthorizationExample
  Install-Package Microsoft.Owin.Security.OAuth -projectname TokenAuthorizationExample
  Install-Package Microsoft.Owin.Cors -projectname TokenAuthorizationExample
  Install-Package Newtonsoft.Json -projectname TokenAuthorizationExample
  Install-Package Microsoft.AspNet.Identity.EntityFramework -Version 2.2.2 -projectname TokenAuthorizationExample


4.在 App_start 中 WebApiConfig.cs 檔增加 2 行程式

預設以 Json 傳回

\App_Start\WebApiConfig.cs
using System.Linq;
using System.Web.Http;

namespace TokenAuthorizationExample
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 設定和服務

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
            config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
        }
    }
}




5.加 Class

5.1
\AuthorizationServerProvider.cs
using System.Security.Claims;
using System.Threading.Tasks;

using Microsoft.Owin.Security.OAuth;

namespace TokenAuthorizationExample
{
    public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }
        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var identity = new ClaimsIdentity(context.Options.AuthenticationType); // 取得身份聲明資料
            if(context.UserName == "admin" && context.Password == "admin") {
                identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
                identity.AddClaim(new Claim("username", "admin"));
                identity.AddClaim(new Claim(ClaimTypes.Name, "morseAdmin"));
                context.Validated(identity);
            }
            else if(context.UserName == "user" && context.Password == "user") {
                identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
                identity.AddClaim(new Claim("username", "user"));
                identity.AddClaim(new Claim(ClaimTypes.Name, "morseUser"));
                context.Validated(identity);
            }
            else {
                context.SetError("Invalid_grant", "Provided username and password is incorrect.");
                return;
            }
        }
    }
}


5.2
\Startup.cs
using System;
using System.Web.Http;

using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.OAuth;

using Owin;

[assembly: OwinStartup(typeof(TokenAuthorizationExample.Startup))]

namespace TokenAuthorizationExample
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // 如需如何設定應用程式的詳細資訊,請瀏覽 https://go.microsoft.com/fwlink/?LinkID=316888
            // enable cors origin requests
            app.UseCors(CorsOptions.AllowAll);

            var myProvider = new AuthorizationServerProvider();
            OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = myProvider
            };
            app.UseOAuthAuthorizationServer(options);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

            HttpConfiguration config = new HttpConfiguration();
            WebApiConfig.Register(config);
        }
    }
}


5.3
\AuthorizeAttribute.cs
using System.Web;
using System.Web.Http.Controllers;

namespace TokenAuthorizationExample
{
    public class AuthorizeAttribute : System.Web.Http.AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
        {
            if(!HttpContext.Current.User.Identity.IsAuthenticated)
                base.HandleUnauthorizedRequest(actionContext);
            else
                actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
        }
    }
}




6.加 Controller

\Controllers\DataController.cs
using System;
using System.Linq;
using System.Security.Claims;
using System.Web.Http;

namespace TokenAuthorizationExample.Controllers
{
    public class DataController : ApiController
    {
        [AllowAnonymous]
        [HttpGet]
        [Route("api/data/getall")]
        public IHttpActionResult Get()
        {
            return Ok("Now server time is: " + DateTime.Now.ToString());
        }
        [Authorize]
        [HttpGet]
        [Route("api/data/hello")]
        public IHttpActionResult GetHello()
        {
            var identity = (ClaimsIdentity)User.Identity;
            return Ok("Hellow " + identity.Name);
        }
        [Authorize(Roles = "admin")]
        [HttpGet]
        [Route("api/data/GetForAdmin")]
        public IHttpActionResult GetForAdmin()
        {
            var identity = (ClaimsIdentity)User.Identity;
            var role = identity.Claims
                .Where(c => c.Type == ClaimTypes.Role)
                .Select(c => c.Value);
            return Ok("Hellow " + identity.Name + ", Role: " + string.Join(",", role.ToList()));
        }
    }
}


7.測試

AllowAnonymous (不控管權限) 可以正常取得資料



取得 admin 令牌 (token)


以 admin 令牌 (token) 取得以 Authorize 控管權限的資料


以 admin 令牌 (token) 取得以 Authorize(Roles = "admin") 控管權限的資料





取得 user 令牌 (token)



METH: POSTHEADERS:             Content-Type: application/x-www-form-urlencodedBODY:             username: 你的帳號             password: 你的密碼             grant_type: password




 以 user 令牌 (token) 取得以 Authorize 控管權限的資料




METH: GETHEADERS:             Authorizationbearer [token access code]





 以 user 令牌 (token) 取得以 Authorize(Roles = "admin") 控管權限的資料時傳回 Http 403 。