Friday, September 4, 2015

Securing WebApi with OWIN Identity Authentication server

 ASP.NET   IDENTITY   Token based authentication   Web Api

▌背景

當完成了OWIN Identity的Authentication Server後,我們已可認證並取得Token。
下一步當然是利用加入Token認證機制到其他的Http Restful Service。



如此在SOA或SP的架構下,可降低Authentication server和Resource serer的耦合性。

PS. 在實作本篇程式碼之前,必須先建立一個Identity Authentication Service。 可參考相關文章建立。

▌相關文章


▌環境

l   Visual Studio 2015
l   WEB API 2.2
l   Entity Framework 6



▌實作


▋Packages we need

先安裝相關套件:
Microsoft.OWIN.Host.SystemWeb
MIcrosoft.AspNet.Identity.Owin
Microsoft.Owin.Security.OAuth
Microsoft.Owin.Security
Microsoft.AspNet.WebApi.Cors


▋OWIN Startup.cs

先移除預設WebApi的Register方法,


l   Global.asax

protected void Application_Start()
{
            AreaRegistration.RegisterAllAreas();
            //GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
}


l   OWIN Startup

public partial class Startup
    {

        public void Configuration(IAppBuilder appBuilder)
        {
            HttpConfiguration config = new HttpConfiguration();

            //Configure OAuth
            this.configureOAuth(appBuilder);

            //Configure WebApi
            this.configureWebApi(appBuilder);
        }

        private void configureOAuth(IAppBuilder app)
        {
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
            {
            });

        }

       
        private void configureWebApi(IAppBuilder app)
        {
            var config = new HttpConfiguration();

            // Configure Web API to use only bearer token authentication.
          config.SuppressDefaultHostAuthentication();
          config.Filters.Add(
                new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));


            // Web API routes
            config.MapHttpAttributeRoutes();

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

            //Enable CORS
            config.EnableCors();

            app.UseWebApi(config);
        }
    }



▋Securing Http Restful Service

最後,只要在我們的WebApi Http方法上加上 [Authorize] ,表示此方法需要經過認證的Request才可使用。

[Authorize]
[HttpGet]
public IEnumerable<string> Get()
{ 
return new string[] { "The website is protected by an authentication server. @2015" };
}



▌測試



▋Testing in IIS Express

環境為:
Authentication Service is on http://localhost:7531
Resource Service (Web Api) is on http://localhost:3241

如下圖,先取得token後,在第一次送出Get並無夾帶token,因此回應為401。
夾帶token後再次request,認證成功可取得資源。





▋Testing in physical IIS at different servers

接下來,我嘗試將Authentication Server和Resource Server分開到兩台不同的機器;
將DB Connection和URL調整後,重新做一次測試。

備註:
在佈署後,送出要求token時出現 401的錯誤。

確認Http及DB連線及防火牆都沒有問題的情況下,偶然在Authentication Service的Application Start加入查詢資料庫的程式碼;
重啟Authentication Service後,再次送出Request給它,此時正常取得資料庫資料,並且Authentication Service的授權功能恢復正常,可正常取得token。

我猜想可能的原因在於使用EF Code first的情況下,必須由第一次作動EF來建立AP和DB之間的連線,否則Authentication Server會一直回傳401。

另因為兩個服務在不同的機器,所以必須產生Machine key後,再加入到兩個服務的Web Config。

<system.web>
    <compilation debug="true" targetFramework="4.5.2" />
    <httpRuntime targetFramework="4.5.2" />
    <!--<authentication mode="None" />-->
    <machineKey validationKey="…"
decryptionKey="…"
validation="SHA1" decryption="AES"/>
</system.web>


測試結果如下,我是把Web Api (Resource Server)放在localhost, Authentication Server放在另一台開發機器。







▌Reference






No comments:

Post a Comment