次の方法で共有


Using LightSwitch ServerApplicationContext and WebAPI to Get User Permissions

Last post I showed a simple way of checking a single user permission from an HTML client screen in order to disable/enable UI elements. If you only have a couple permissions to check and you don’t want to write a lot of code then this simple tip works. However, if you need to check many permissions throughout your HTML client app or you need to return permissions to custom web clients you build against the LightSwitch server, a better idea is to retrieve all these permissions at once for the logged in user and store them on the client so all screens can access them without hitting the database again.

The LightSwitch philosophy is to provide RAD tools for building business apps fast, but still allow advanced customization where and when you need it. In this post I’ll show you a way to return user permissions by creating a custom web method using Web API and the LightSwitch ServerApplicationContext that was introduced in Visual Studio 2012 Update 2. If you missed Matt’s post about it, check it out here: Using the LightSwitch ServerApplicationContext API

You can download the sample code from this post here.

Create Permissions and Secure your Data

The first step in securing your data based on user permissions is to define your permissions and check them from the entity access control methods. For this example, we will define a couple permissions “CanAddCustomer” and “CanEditCustomer” that determines whether a user can perform Inserts and Edits on a Customer entity on the server.

Open the Project Properties and define your permissions. Make sure to enable authentication. Then check off the permissions you want to enable while you’re debugging.

image_thumb[1]

Then in the data designer, select the Server perspective and then drop down the “Write Code” button and select the Customers_CanInsert and Customers_CanUpdate access control methods:

image

Then you write code like this to allow or disallow the insertion and editing of customers:

VB:

 Private Sub Customers_CanInsert(ByRef result As Boolean)
    result = Me.Application.User.HasPermission(Permissions.CanAddCustomer)
End Sub

Private Sub Customers_CanUpdate(ByRef result As Boolean)
    result = Me.Application.User.HasPermission(Permissions.CanEditCustomer)
End Sub

C#:

 partial void Customers_CanInsert(ref bool result)
{
    result = this.Application.User.HasPermission(Permissions.CanAddCustomer);
}

partial void Customers_CanUpdate(ref bool result)
{
    result = this.Application.User.HasPermission(Permissions.CanEditCustomer);
}

 

You always want to secure the server-side this way in order to protect the data in your system. However, sometimes we also want to use a permission check in the UI in order to hide/unhide (or enable/disable) elements on a multitude of screens.

As I mentioned in my previous post, the Silverlight desktop client exposes a User object available to you at all times from any screen, so checking permissions on the client is easy. Here’s how you can create a similar object for the HTML client that holds all the permissions for a logged in user.

Create a Custom Web API on the LightSwitch Server

First we’re going to use Web API to expose a RESTful service that will return JSON to the client. Flip to the file view in the Solution Explorer.

image_thumb[4]

Add a folder called “Perms” (or whatever you want to call it) to the Server project , add an new item, and select Web API Controller Class and name it “UserPermissionsController”.

image_thumb[3]

Now we can use the LightSwitch ServerApplicationContext to verify the user is authenticated and to create a dictionary of their own permissions. If the user is not authenticated then nothing is returned. Note that you will need to add references to the LightSwitch Server and Security namespaces first.

In order to query the LightSwitch SecurityData where the permission data resides we need to temporarily elevate the caller’s permissions. This elevation is only in effect during the extent of the execution of the method. For more information about permission elevation see: How to Elevate Permissions in Server Code

Be careful what you put in this dictionary. Here we are simply populating a list of permissions, we’re not putting any sensitive information in there like the user’s name or passwords. Remember with power comes responsibility.

VB:

 Imports System.Net
Imports System.Web.Http
Imports LightSwitchApplication
Imports Microsoft.LightSwitch.Server
Imports Microsoft.LightSwitch.Security

Public Class UserPermissionsController
    Inherits ApiController

    ' GET api/<controller>
    Public Function GetValues() As Dictionary(Of String, Boolean)
        'This will generically retrieve all the permissions of the current logged in user. 

        Dim perms As New Dictionary(Of String, Boolean)

        Using ctx As ServerApplicationContext = ServerApplicationContext.CreateContext()
            Dim currentUser = ctx.Application.User

            'If the requestor is not logged in then nothing is returned. 
            ' Only properly logged in users can retrieve their own permissions
            If currentUser.IsAuthenticated Then

                perms.Add(Permissions.SecurityAdministration,
                          currentUser.HasPermission(Permissions.SecurityAdministration))

                'elevate permissions temporarily
                currentUser.AddPermissions(Permissions.SecurityAdministration)

                For Each perm As Permission In ctx.DataWorkspace.SecurityData.Permissions()
                    If perm.Id <> Permissions.SecurityAdministration Then

                        perms.Add(perm.Id, currentUser.HasPermission(perm.Id))
                    End If
                Next
            End If
        End Using

        Return perms
    End Function

End Class

 

C#:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Microsoft.LightSwitch.Server;
using Microsoft.LightSwitch.Security;
using Microsoft.LightSwitch.Security.Server;
using LightSwitchApplication;

namespace LightSwitchApplication.Perms
{
    public class UserPermissionsController : ApiController
    {
        // GET api/<controller>
        public Dictionary<string, Boolean> Get()
        {
            Dictionary<string, Boolean> perms = new Dictionary<string, Boolean>();

            using (ServerApplicationContext ctx = ServerApplicationContext.CreateContext())
            {
                var currentUser = ctx.Application.User;
                if (currentUser.IsAuthenticated)
                {
                    perms.Add(Permissions.SecurityAdministration,
                        currentUser.HasPermission(Permissions.SecurityAdministration));

                    currentUser.AddPermissions(Permissions.SecurityAdministration);

                    foreach (Permission perm in ctx.DataWorkspace.SecurityData.Permissions)
                    {
                        if (perm.Id != Permissions.SecurityAdministration)
                        {
                            perms.Add(perm.Id, currentUser.HasPermission(perm.Id));
                        }
                    }
                }
            }
            return perms;
        }
    }
}

Finally we need to add a route to our controller. Right-click on the server project again and add a Global Application Class (Global.asax) and add the following references at the top:

VB:

 Imports System.Web.Http
Imports System.Web.Routing

C#:

 using System.Web.Routing;
using System.Web.Http; 

Then in the Application_Start method add the route.

VB:

 Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
    ' Fires when the application is started
    RouteTable.Routes.MapHttpRoute("PermsApi", "Perms/{controller}")
End Sub

C#:

 protected void Application_Start(object sender, EventArgs e)
{
    RouteTable.Routes.MapHttpRoute("PermsApi", "Perms/{controller}");
}

Retrieve the Permissions on the Client

Next we need to call this method from the client and save the data in a global object. On the LightSwitch HTML client there is a global object called myapp that we can use to store the permissions object. You can use the myapp object in a variety of ways in order to access data and screens in the HTML client. Check out some other uses here- How to: Modify an HTML Screen by Using Code

The handiest place to put the code to retrieve the permissions is in the created method on the first screen in our application. This is the first user method that will be called when the app starts and we can be sure that the LightSwitch client environment is ready.

Open the screen that is set as your Home screen (this is probably the first screen you created or you can right-click on a screen in the Solution Explorer and “Set as Home Screen”). Select the Screen node at the top of the content tree, drop down the “Write Code” button, and select the created method.

image

Here’s the code that will call the web API and return a JSON object with the permissions.

 myapp.BrowseCustomers.created = function (screen) {
    // Write code here.
    $.getJSON("../Perms/UserPermissions/", function (data) {

        //attach the permissions to the global 'myapp' object 
        //so it is accessible to the client anywhere.
        myapp.permissions = data;
     });    
};

Put a breakpoint here and notice that the dictionary of permissions is returned when you run it.

image_thumb[5]

 

Check the Permissions in JavaScript Code

Now that we have the set of permissions on the client we can check permissions anywhere in our HTML screens by writing some simple JavaScript. In my example I want to enable/disable buttons on a screen depending on whether the user can add or edit Customers.

First take note of the control names you want to manipulate. In my case I have a couple buttons one named AddCustomer and another named EditCustomer.

image_thumb[6]

Just like before, select the Screen node at the top of the content tree, drop down the “Write Code” button, and select the created method for that screen. Then write code to check the permissions object:

 if (myapp.permissions["LightSwitchApplication:CanAddCustomer"]) {
    screen.findContentItem("AddCustomer").isEnabled = true;
}
else {
    screen.findContentItem("AddCustomer").isEnabled = false;
}
if (myapp.permissions["LightSwitchApplication:CanEditCustomer"]) {
    screen.findContentItem("EditCustomer").isEnabled = true;
}
else {
    screen.findContentItem("EditCustomer").isEnabled = false;
}

Now we can see that buttons are correctly enabled & disabled based on the permissions.

image_thumb[8]

Wrap Up

LightSwitch is all about productivity and we strive to provide the best developer experience for building business apps as fast as possible. However we also want to allow advanced customization and power where and when you need it. Whether that’s implementing custom controls, data sources, web services, etc.  -- there is a lot of room for extensibility, especially in the latest version (V3) of LightSwitch in Visual Studio 2012 Update 2.

There are a lot of possibilities that are available to you now that we’ve opened up the LightSwitch API on the server using the ServerApplicationContext. Coupled with the ease of using Web API you can provide custom service interfaces to your LightSwitch server logic to provide smart, custom, RESTful HTTP services to a host of clients.

With this practical example, I hope I not only showed you how to retrieve user permissions but also gave you a glimpse of what is possible. Stay tuned to the LightSwitch Team blog for more examples like dashboards and reporting scenarios.

Enjoy!

Comments

  • Anonymous
    April 17, 2013
    The comment has been removed

  • Anonymous
    April 17, 2013
    Good explanation Beth......any solution  for the users registration ?

  • Anonymous
    April 19, 2013
    hey Beth can you please help me about my msdn forum account i see it is banned and there is no reason can you check the issue ? thank you social.msdn.microsoft.com/.../monstermmorpg

  • Anonymous
    April 21, 2013
    Beth, Are you using a newer build than the latest VS2012 Update 2? I cannot find the AddPermissions method on IUser.

  • Anonymous
    April 21, 2013
    Oops!! I couldn't find AddPermissions because I was missing a namespace...

  • Anonymous
    April 22, 2013
    good one.....it helped me ...

  • Anonymous
    April 23, 2013
    Incredibly helpful!

  • Anonymous
    May 24, 2013
    Thanks Beth, but how can I disable standard Save button in Edit dialog?

  • Anonymous
    June 06, 2013
    Hey Beth I just have a question : is this solution is secured? Can anybody see this Javascript?

  • Anonymous
    June 07, 2013
    @Rom -- the JS simply makes a call to the server. The server code is compiled and cannot be seen. But keep in mind that whoever makes the call must already be authenticated -- that's already happened once you get there. Also notice that I'm not returning any usernames/passwords in the JSON so it's not identifiable.

  • Anonymous
    June 19, 2013
    How do you set the users permissions?

  • Anonymous
    June 25, 2013
    @Robert - In this release in order to manage user's and roles, first add a desktop client to your solution (right-click on the solution and "Add client". Then when you deploy your app, you will get the administration screens. If you want to see the admin screens while debugging, grant for debug the SecurityAdministration permission on the Access Control tab of the project properties.

  • Anonymous
    July 10, 2013
    Hi, I added this code to my project, its works perfectly on my development machine in both debug and release modes, but when I deploy the app to Azure the client query fails to return the permissions. Have you any idea what I might have missed?

  • Anonymous
    July 12, 2013
    Hi AirBear, This is working fine for me in Azure. Perhaps you haven't entered the user permissions into the system yet? When you deploy with authentication you also need to deploy an administration console to manage the users. See this post: blogs.msdn.com/.../how-to-assign-users-roles-and-permissions-to-a-lightswitch-html-mobile-client.aspx Cheers, -Beth

  • Anonymous
    October 16, 2013
    Hi Beth :) Great article thanks - just have one problem. I currently have the code to get the permissions in my startup switchboard page. The code to then check permissions is in the clients pop up screen - this enables/disables the add button which works fine. I then tried putting the check permissions code in the startup page so I can switch the visibility of groups of buttons depending on the logged on user's permissions. This fails however fails due to myapp.permissions not being defined. On checking I can see that the server side code hasn't run yet when the JS is checking permissions. Is there a way around this please. Thanks so much Tim x

  • Anonymous
    November 19, 2013
    Hi, Is it possible to use this to restrict access to entire screens in a similar way to the destop client?

  • Anonymous
    January 24, 2014
    Beth thank you for all the documentation, I finally got past some breakpoints not getting hit. But now when I run this code. myapp.BrowseQryParcels.created = function (screen) {    //alert("Hello World");    // Write code here.    $.getJSON("../Perms/UserPermissions/", function (data) {        alert("Hello World 2");        //attach the permissions to the global 'myapp' object        //so it is accessible to the client anywhere.        myapp.permissions = data;        alert(myapp.permissions);    }); }; When it gets to myapp.permissions = data; it shows as undefined. Any thoughts. I have followed and double check everything else in this post and it looks fine. I am running VS 2013 on Win 7 x64. Thoughts?

    • Anonymous
      February 12, 2017
      Hi Ken,How did you solved your problem of breakpoint not getting hit in your javaScript code. ? I have gone through many articles but all in vain. Any help on this will be appreciated. Regardsw_billa
  • Anonymous
    June 12, 2014
    Hi Beth, Thanks for this. However might I point out that this implementation is flawed slightly. By only placing this on the startup screen, the myapp.permissions won't be populated if a user refreshes the browser on any other screen. Something we found out during a publish to live. Sad sad face goes here. Regards to the Team. Still really enjoying Lightswitch a lot, just not enjoying the lack of up-do-date documentation. Is there a way we can put unilateral pressure for you guys to get more resources for technical writing and useful msdn moderation (your current moderators just seem to mark the closest thing to an answer as an answer in many places and some people just don't bother responding to tell them its not the answer)? Release notes, official roadmap, updated api/dom docs, etc would be really useful. Version fail of msls2.5.0 was a small disaster too. Even the latest api client reference examples are flawed or out of date (e.g. implementation of handleviewdisposed). It would be foolish of the new big boss man not to throw some resources into this goldmine you guys are excavating. Besides the frustration researching troubleshoots, yeah, loving it :) Thanks and kind regards, Grant Clark

  • Anonymous
    October 28, 2014
    Hi Beth! I have a question.  I have a ODATA Connector and a separate light switch application which uses this Odata Connector. I need to set up permission on Odata connector ( like read and edit) so that it should reflect on my light switch app. any idea how to achieve this? I have researched many articles but could not get an idea. Please help.

  • Anonymous
    May 05, 2015
    Hi Beth, Great article on how to call a list of available permissions for currentUser really useful. I have one question,  after temporary elevating the user and going through the list of permissions to build your dictionary of permissions,  do you need to then do currentUser.RemovePermissions(Permissions.SecurityAdministration); ?   or does it clean up itself after this api method call? Your guidance is greatly appreciated.  : )

  • Anonymous
    August 11, 2015
    Am getting an error in my browser that ; TypeError; to the "LightswicthApplication: CanAddCustomers" i have done this example more than 5 times even with the exart detail code used and the diagrams-everything. But still it can't even run!!! Someone Help Plz if yours worked.

  • Anonymous
    August 11, 2015
    Thanks Found it out......i was place the if condition out of the myapp.BrowseCustomer_Created{ }; that's why now its fine. amana implement it in my projects. Gratitudes Beth Massi

  • Anonymous
    December 26, 2015
    Is there any way to make the permission of a web LS app from desktop project: How to identify the permission of a persion from log-in page ? Some of the UI elements may be hide for different persons who have different permissions ?