[]
Complete the following steps to create a customized authorization for controlling the file access permissions.
In your application, you need to add files that define which role can access the folder, as shown in the image below. Once you have added the _roles file, you can read the roles information in authorization attribute.
To provide access to the folders based on the role assigned to the user, read the roles information in the authorization attribute. The authorization attribute identifies the user login and provides access to the files based on the role assigned to the users.
In the Solution Explorer, right click project and select Add | Class. The Add New Item dialog appears.
In the Add New Item dialog, set the name of the class (for example: StorageAuthorizeAttribute.cs).
Click Add. A new class is added to the application.
Add the following code inside StorageAuthorizeAttribute.cs file.
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);
}
}
}
In the Solution Explorer, right click the folder Controllers.
From the context menu, select Add | Controller. The Add Scaffold dialog appears.
Complete the following steps in the Add Scaffold dialog:
ReportController
).Add the following code inside ReportController.cs file.
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);
}
}
}
In the Solution Explorer, right click project and select Add | Class. The Add New Item dialog appears.
In the Add New Item dialog, set the name of the class (for example: CustomDirectRouteProvider.cs).
Click Add. A new class is added to the application.
Add the following code inside CustomDirectRouteProvider.cs file.
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)
{
// inherit route attributes decorated on base class controller's actions
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;
}
}
}
There are two ReportControllers in this application. This code adds a customized IHttpControllerTypeResolver which helps the client application to identify the required ReportController at the time of execution.
In the Solution Explorer, right click project and select Add | Class. The Add New Item dialog appears.
In the Add New Item dialog, set the name of the class (for example: ReportsControllerTypeResolver.cs).
Click Add. A new class is added to the application.
Add the following code inside ReportsControllerTypeResolver.cs file.
using System;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
namespace SalesReport
{
internal class ReportsControllerTypeResolver : DefaultHttpControllerTypeResolver
{
public ReportsControllerTypeResolver() : base(IsControllerType)
{ }
private static bool IsControllerType(Type t)
{
if (t != null && t.IsClass && (t.IsVisible && !t.IsAbstract) && typeof(IHttpController).IsAssignableFrom(t))
return HasValidControllerName(t) && t != typeof(C1.Web.Api.Report.ReportController);
return false;
}
private static bool HasValidControllerName(Type controllerType)
{
string str = DefaultHttpControllerSelector.ControllerSuffix;
if (controllerType.Name.Length > str.Length)
return controllerType.Name.EndsWith(str, StringComparison.OrdinalIgnoreCase);
return false;
}
}
}
Register the HttpConfiguration in WebApiConfig.cs file. Also, configure the Web API to use only bearer token authentication.
In the Solution Explorer, right click AppData folder and select Add | Class. The Add New Item dialog appears.
In the Add New Item dialog, set the name of the class (for example: WebApiConfig.cs).
Click Add. A new class is added to the application.
Add the following code inside WebApiConfig.cs file.
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 configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
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());
}
}