Serenity: ServiceEndpoints permissions

Created on 28 Mar 2016  路  7Comments  路  Source: serenity-is/Serenity

can permissions be set over actions in ServiceEndpoints services
such as user cant export to excel

Most helpful comment

Thanks Volkan. I missed that part.

Zerodev, did you get this working?

Here's how I did it.

In PermissionKeys.cs define a permission for Excel
(note that I re-arranged this class from the default and adjusted other files accordingly)

namespace TESTPROJECT
{
    public class PermissionKeys
    {
        public class Administration
        { 
            public const string Security = "Administration:Security";
            public const string Translation = "Administration:Translation";
        }

        public class Agency
        {
            public const string Create = "Agency:Create";
            public const string Read = "Agency:Read";
            public const string Update = "Agency:Update";
            public const string Delete = "Agency:Delete";
            public const string Page = "Agency:Page";
            public const string Excel = "Agency:Excel";
        }

    }
}

In site.texts.invariant.json, define your dialog UI text

{
  "Navigation.Dashboard": "Dashboard",
  "Permission.Administration:": "Administration",
  "Permission.Administration:Security": "User, Role Management and Permissions",
  "Permission.Administration:Translation": "Languages and Translations",
  "Permission.Agency:": "Agency",
  "Permission.Agency:Create": "Create",
  "Permission.Agency:Read": "Read",
  "Permission.Agency:Update": "Update",
  "Permission.Agency:Delete": "Delete",
  "Permission.Agency:Page": "View Agency Page",
  "Permission.Agency:Excel": "Export Agency Grid as Excel"
}

In your Script project, change your grid file to only show the excel button if they have your permission

namespace TESTPROJECT.Tables
{
    using jQueryApi;
    using Serenity;
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;

    [ColumnsKey("Tables.Agency"), IdProperty(AgencyRow.IdProperty), NameProperty(AgencyRow.NameProperty)]
    [DialogType(typeof(AgencyDialog)), LocalTextPrefix(AgencyRow.LocalTextPrefix), Service(AgencyService.BaseUrl)]
    public class AgencyGrid : EntityGrid<AgencyRow>
    {
        public AgencyGrid(jQueryObject container)
            : base(container)
        {
        }

        //Add button to export to Excel
        protected override List<ToolButton> GetButtons()
        {
            var buttons = base.GetButtons();
            if (Authorization.HasPermission("Agency:Excel"))
            {
                buttons.Add(Common.ExcelExportHelper.CreateToolButton(this,
                AgencyService.BaseUrl + "/ListExcel", this.OnViewSubmit));
            }
            return buttons;
        }
    }
}

and in your module's endpoint.cs file, set the permission in a ServiceAuthorize attribute above your ListExcel action method so they can't bypass the button and use javascript to invoke the excel export.

[RoutePrefix("Services/Tables/Agency"), Route("{action}")]
[ConnectionKey("Default")]
public class AgencyController : ServiceEndpoint
{
    [HttpPost]
    public SaveResponse Create(IUnitOfWork uow, SaveRequest<MyRow> request)
    {
        return new MyRepository().Create(uow, request);
    }

    [HttpPost]
    public SaveResponse Update(IUnitOfWork uow, SaveRequest<MyRow> request)
    {
        return new MyRepository().Update(uow, request);
    }

    [HttpPost]
    public DeleteResponse Delete(IUnitOfWork uow, DeleteRequest request)
    {
        return new MyRepository().Delete(uow, request);
    }

    public RetrieveResponse<MyRow> Retrieve(IDbConnection connection, RetrieveRequest request)
    {
        return new MyRepository().Retrieve(connection, request);
    }

    public ListResponse<MyRow> List(IDbConnection connection, ListRequest request)
    {
        return new MyRepository().List(connection, request);
    }

    [ServiceAuthorize(PermissionKeys.Agency.Excel)]
    public FileContentResult ListExcel(IDbConnection connection, ListRequest request)
    {
        var data = List(connection, request).Entities;
        var report = new DynamicDataReport(data, request.IncludeColumns, typeof(Columns.AgencyColumns));
        var bytes = new ReportRepository().Render(report);
        return ExcelContentResult.Create(bytes, "AgencyList_" +
            DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".xlsx");
    }


}

Hope this helps.

All 7 comments

add ServiceAuthorize attribute with desired permission to action method directly

Volkan, in addition to the ServiceAuthorize attribute, is there a way to add another level of permissions? So you end up with something like

Administration:Translation:List
Administration:Translation:Save

maybe in the PermissionKeys.cs and Site.Text.Invariant.Json files?
It would be nice to select these individual permissions in the permissions dialog.

Thanks Volkan. I missed that part.

Zerodev, did you get this working?

Here's how I did it.

In PermissionKeys.cs define a permission for Excel
(note that I re-arranged this class from the default and adjusted other files accordingly)

namespace TESTPROJECT
{
    public class PermissionKeys
    {
        public class Administration
        { 
            public const string Security = "Administration:Security";
            public const string Translation = "Administration:Translation";
        }

        public class Agency
        {
            public const string Create = "Agency:Create";
            public const string Read = "Agency:Read";
            public const string Update = "Agency:Update";
            public const string Delete = "Agency:Delete";
            public const string Page = "Agency:Page";
            public const string Excel = "Agency:Excel";
        }

    }
}

In site.texts.invariant.json, define your dialog UI text

{
  "Navigation.Dashboard": "Dashboard",
  "Permission.Administration:": "Administration",
  "Permission.Administration:Security": "User, Role Management and Permissions",
  "Permission.Administration:Translation": "Languages and Translations",
  "Permission.Agency:": "Agency",
  "Permission.Agency:Create": "Create",
  "Permission.Agency:Read": "Read",
  "Permission.Agency:Update": "Update",
  "Permission.Agency:Delete": "Delete",
  "Permission.Agency:Page": "View Agency Page",
  "Permission.Agency:Excel": "Export Agency Grid as Excel"
}

In your Script project, change your grid file to only show the excel button if they have your permission

namespace TESTPROJECT.Tables
{
    using jQueryApi;
    using Serenity;
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;

    [ColumnsKey("Tables.Agency"), IdProperty(AgencyRow.IdProperty), NameProperty(AgencyRow.NameProperty)]
    [DialogType(typeof(AgencyDialog)), LocalTextPrefix(AgencyRow.LocalTextPrefix), Service(AgencyService.BaseUrl)]
    public class AgencyGrid : EntityGrid<AgencyRow>
    {
        public AgencyGrid(jQueryObject container)
            : base(container)
        {
        }

        //Add button to export to Excel
        protected override List<ToolButton> GetButtons()
        {
            var buttons = base.GetButtons();
            if (Authorization.HasPermission("Agency:Excel"))
            {
                buttons.Add(Common.ExcelExportHelper.CreateToolButton(this,
                AgencyService.BaseUrl + "/ListExcel", this.OnViewSubmit));
            }
            return buttons;
        }
    }
}

and in your module's endpoint.cs file, set the permission in a ServiceAuthorize attribute above your ListExcel action method so they can't bypass the button and use javascript to invoke the excel export.

[RoutePrefix("Services/Tables/Agency"), Route("{action}")]
[ConnectionKey("Default")]
public class AgencyController : ServiceEndpoint
{
    [HttpPost]
    public SaveResponse Create(IUnitOfWork uow, SaveRequest<MyRow> request)
    {
        return new MyRepository().Create(uow, request);
    }

    [HttpPost]
    public SaveResponse Update(IUnitOfWork uow, SaveRequest<MyRow> request)
    {
        return new MyRepository().Update(uow, request);
    }

    [HttpPost]
    public DeleteResponse Delete(IUnitOfWork uow, DeleteRequest request)
    {
        return new MyRepository().Delete(uow, request);
    }

    public RetrieveResponse<MyRow> Retrieve(IDbConnection connection, RetrieveRequest request)
    {
        return new MyRepository().Retrieve(connection, request);
    }

    public ListResponse<MyRow> List(IDbConnection connection, ListRequest request)
    {
        return new MyRepository().List(connection, request);
    }

    [ServiceAuthorize(PermissionKeys.Agency.Excel)]
    public FileContentResult ListExcel(IDbConnection connection, ListRequest request)
    {
        var data = List(connection, request).Entities;
        var report = new DynamicDataReport(data, request.IncludeColumns, typeof(Columns.AgencyColumns));
        var bytes = new ReportRepository().Render(report);
        return ExcelContentResult.Create(bytes, "AgencyList_" +
            DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".xlsx");
    }


}

Hope this helps.

Just a little note, don't remove ServiceAuthorize from controller itself. Even though permissions on row are also checked on request handlers, if you add a custom method to endpoint, and forgot to add ServiceAuthorize to it, anyone can call that method.

Good point. Thanks.

@scottcottingham thank what I did at first is @volkanceylan method , now I changed to have both ways , I liked removing the button , now trying to find a way to filter data based on current login user

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dkontod picture dkontod  路  3Comments

kilroyFR picture kilroyFR  路  3Comments

JohnRanger picture JohnRanger  路  3Comments

newyearsoft picture newyearsoft  路  3Comments

Amitloh picture Amitloh  路  3Comments