ASP.NET Web API コントロール
手順2 : カスタム認証の追加
ComponentOne for Web API > WebAPIサービスのセキュリティ > 手順2 : カスタム認証の追加

ファイルアクセス許可を制御するためのカスタム認証を作成するには、次の手順を実行します。

フォルダのアクセス許可の設定

下の画像に示すように、アプリケーションのフォルダにアクセスできるロールを定義するファイルを追加する必要があります。 _rolesファイルを追加すると、承認属性でロール情報を読み取ることができます。

ユーザーに割り当てられた役割に基づいてフォルダへのアクセス権限を付与するには、認証属性の役割情報を参照してください。認証属性はユーザーのログイン情報を識別し、ユーザーに割り当てられた役割に基づいてファイルへのアクセスを提供します。

  1. ソリューションエクスプローラーで、プロジェクトを右クリックし、[追加]→[クラス]を選択します。「新しい項目の追加」ダイアログが表示されます。   
  2. 「新しい項目の追加」ダイアログで、クラス名を設定します(例:StorageAuthorizeAttribute.cs)。
  3. 追加 をクリックします。
  4. StorageAuthorizeAttribute.csファイルに次のコードを追加します。
    StorageAuthorizeAttribute.cs
    コードのコピー
    using C1.Web.Api.Report;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Web.Http.Controllers;
    using System.Web.Http.Filters;
    using C1.Web.Api.Storage;
    
    namespace SalesReport.Controllers
    {
        internal class StorageAuthorizeAttribute : AuthorizationFilterAttribute
        {
            public override void OnAuthorization(HttpActionContext actionContext)
            {
       var principal = actionContext.ControllerContext.RequestContext.Principal;
             if (principal == null || principal.Identity == null || 
             !principal.Identity.IsAuthenticated)
                {
                    Unauthorize(actionContext);
                    return;
                }
    
                var values = actionContext.RequestContext.RouteData.Values;
                object pathObj;
    
                if (!values.TryGetValue("path", out pathObj))
                {
                    return;
                }
    
                var path = (pathObj as string) ?? string.Empty;
                var defaultProvider = ReportProviderManager.Current.Get("")
             as FlexReportProvider;
                if (defaultProvider == null)
                {
                    return;
                }
    
                var roles = GetRoles(defaultProvider.Storage, path);
                if(!roles.Any())
                {
                    return;
                }
    
                if (!roles.Any(r => principal.IsInRole(r)))
    
                {
                    Unauthorize(actionContext);
                }
            }
    
            private static readonly object _locker = new object();
            private static readonly IDictionary<string, 
          IEnumerable<string>> _folderRoles = 
                new Dictionary<string, IEnumerable<string>>
    
          (StringComparer.OrdinalIgnoreCase);
            private static IEnumerable<string> GetRoles
                            
           (IStorageProvider storage, string path)
            {
                string folder = path;
                var fileStorage = storage.GetFileStorage(path);
                if (fileStorage.Exists)
                {
                    var pathParts = path.Split('/');
                    pathParts = pathParts.Take(pathParts.Length - 1).ToArray();
                    folder = string.Join("/", pathParts);
                }
    
                lock (_locker)
                {
                    IEnumerable<string> roles;
                    if (_folderRoles.TryGetValue(folder, out roles))
                    {
                        return roles;
                    }
    
                    var roleList = GetFolderRoles("", storage);
                    var folderParts = folder.Split(new[] { '/' },
    
         StringSplitOptions.RemoveEmptyEntries);
                    var currentFolder = "";
                    foreach (var part in folderParts)
                    {
                        currentFolder += part;
                        var current = GetFolderRoles(currentFolder, storage);
                        if(current != null && current.Any())
                        {
                            roleList = current;
                        }
    
                        currentFolder += "/";
                    }
    
                    return roleList;
                }
            }
    
            private static IEnumerable<string> GetFolderRoles(string path, 
    
     
                    IStorageProvider storage)
    
            {
                IEnumerable<string> roles;
                if (_folderRoles.TryGetValue(path, out roles))
                {
                    return roles;
                }
    
                var roleList = new List<string>();
                var rolesFile = storage.GetFileStorage(path + "/_.roles");
                if(rolesFile.Exists)
    
                {
                    using (var reader = new StreamReader(rolesFile.Read()))
                    {
                        while (!reader.EndOfStream)
                        {
                            var line = reader.ReadLine();
                            if (!string.IsNullOrEmpty(line))
                            {
                                roleList.Add(line);
                            }
                        }
                    }
                }
    
    
                _folderRoles.Add(path, roleList);
                return roleList;
            }
    
    
            private static void Unauthorize(HttpActionContext actionContext)
    
            {
                actionContext.Response = new System.Net.Http.
    
                       HttpResponseMessage(HttpStatusCode.Unauthorized);
    
            }
        }
    }
    

先頭に戻る

カスタム認証属性でReportControllerのカスタマイズ

  1. ソリューションエクスプローラーで、[Controllers]フォルダを右クリックします。
  2. コンテキストメニューで、[追加]→[新規スキャフォールディングアイテム]を選択します。[スキャフォールディングを追加]ダイアログが表示されます。
  3. スキャフォールディングを追加ダイアログでは、次の手順を実行します。
    1. MVC 5 コントローラー -空 テンプレートを選択します。
    2. コントローラー名を設定します(例: ReportController)。
    3. 追加をクリックします。
  4. ReportController.csファイルに次のコードを追加します。
    ReportController.cs
    コードのコピー
    using System.Web.Http;
    namespace SalesReport.Controllers
    
    {
        public class ReportController : C1.Web.Api.Report.ReportController
        {
            [StorageAuthorize]
            public override IHttpActionResult GetCatalogInfo(string path, 
          bool recursive = false)
    
            {
                return base.GetCatalogInfo(path, recursive);
            }
        }
    }
    

先頭に戻る

ルート属性のIDirectRouteProviderのカスタマイズ

  1. ソリューションエクスプローラーで、プロジェクトを右クリックし、[追加]→[クラス]を選択します。「新しい項目の追加」ダイアログが表示されます。
  2. 「新しい項目の追加」ダイアログで、クラス名を設定します(例:CustomDirectRouteProvider.cs)。
  3. 追加をクリックします。
  4. CustomDirectRouteProvider.csファイルに次のコードを追加します。
    CustomDirectRouteProvider.cs
    コードのコピー
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Http.Controllers;
    using System.Web.Http.Routing;
    
    namespace SalesReport
    
    {
    
        public class CustomDirectRouteProvider : DefaultDirectRouteProvider
    
        {
            protected override IReadOnlyList<IDirectRouteFactory>       
            GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
    
            {
    
                // ベースクラスコントローラのアクションで設定されたルート属性を継承します
    
          return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(true);
    
            }
    
            protected override string GetRoutePrefix(HttpControllerDescriptor 
            
            controllerDescriptor)
    
            {
    
                var prefix = base.GetRoutePrefix(controllerDescriptor);
    
                if (string.IsNullOrEmpty(prefix))
    
                {
    
                    var prefixAttr = controllerDescriptor.GetCustomAttributes
            
            <IRoutePrefix>(true).FirstOrDefault();
    
                    if (prefixAttr != null)
    
                    {
    
                        return prefixAttr.Prefix;
    
                    }
    
                }
    
               return prefix;
            }
        }
    }
    

先頭に戻る

複数のReportControllersの競合の解決

このアプリケーションには2つのReportControllerが用意されています。以下のコードを使用すると、クライアントアプリケーションによって必要なReportControllerを識別するためのカスタマイズされたIHttpControllerTypeResolverが追加されます。

  1. ソリューションエクスプローラーで、プロジェクトを右クリックし、[追加]→[クラス]を選択します。「新しい項目の追加」ダイアログが表示されます。
  2. 「新しい項目の追加」ダイアログで、クラス名を設定します(例:CustomDirectRouteProvider.cs)。
  3. 追加をクリックします。
  4. CustomDirectRouteProvider.csファイルに次のコードを追加します。
    CustomDirectRouteProvider.cs
    コードのコピー
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Http.Controllers;
    using System.Web.Http.Routing;
    
    namespace SalesReport
    {
        public class CustomDirectRouteProvider : DefaultDirectRouteProvider
        {
            protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
            {
                // ベースクラスコントローラのアクションで装飾されたルート属性を継承する
                return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(true);
            }
    
            protected override string GetRoutePrefix(HttpControllerDescriptor controllerDescriptor)
            {
                var prefix = base.GetRoutePrefix(controllerDescriptor);
                if (string.IsNullOrEmpty(prefix))
                {
                    var prefixAttr = controllerDescriptor.GetCustomAttributes<IRoutePrefix>(true).FirstOrDefault();
                    if (prefixAttr != null)
                    {
                        return prefixAttr.Prefix;
                    }
                }
    
                return prefix;
            }
        }
    }
    

WebApiConfigクラスにHttpConfigurationの登録

WebApiConfig.csファイルにHttpConfigurationを登録します。 また、ベアラートークン認証のみを使用するようにWeb APIを構成します。

  1. ソリューションエクスプローラーで、AppDataフォルダ右クリックし、[追加]→[クラス]を選択します。「新しい項目の追加」ダイアログが表示されます。
  2. 新しい項目の追加」ダイアログで、クラス名を設定します(例:WebApiConfig.cs)。
  3. 追加をクリックします。
  4. WebApiConfig.cs ファイルに次のコードを追加します。
    WebApiConfig.cs
    コードのコピー
    using System.Web.Http;
    using Microsoft.Owin.Security.OAuth;
    using System.Web.Http.Dispatcher;
    
    namespace SalesReport
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web APIの設定とサービス
                // ベアラートークン認証のみを使用するようにWeb APIを構成します
                config.SuppressDefaultHostAuthentication();
                config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
    
                // Web API ルート
                config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                config.Services.Replace(typeof(IHttpControllerTypeResolver), new ReportsControllerTypeResolver());
            }
        }
    

先頭に戻る

プロジェクトのビルドおよび実行

  1. [ビルド]→[ソリューションのビルド]をクリックして、プロジェクトをビルドします。
  2. [F5]キーを押してプロジェクトを実行します。

先頭に戻る