1. 建立專案 ( TokenAuthorizationExample.csproj)
新增專案時選擇 ASP.NET Web 應用程式
選擇 Web API
專案建立後系統會生成下圖的內容
2.啟用 SSL
點選 [方案總管] 中的專案名稱 (TokenAuthorizationExample),然後在屬性視窗中啟用 SSL。
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(Roles = "admin") 控管權限的資料
取得 user 令牌 (token)
METH: POSTHEADERS: Content-Type: application/x-www-form-urlencodedBODY: username: 你的帳號 password: 你的密碼 grant_type: password
METH: GETHEADERS: Authorization: bearer [token access code]
以 user 令牌 (token) 取得以 Authorize(Roles = "admin") 控管權限的資料時傳回 Http 403 。