Permission-Based Webpart Binding in SPFx

Introduction

 
Permissions are the most important part of web development, dealing with who can view something who cannot. In this article, I will elaborate on how to use permission levels in SPFX development.
 
 
To check whether a user is a Tenant admin: 
  1. this.context.pageContext.legacyPageContext['isSiteOwner'];  
To check whether user is an Site collection Administrator:
  1. this.context.pageContext.legacyPageContext.isSiteAdmin;    
LegacyPageContext is a powerful context where we can get more info about Sharepoint for free. The available objects are: 
  1. webServerRelativeUrl: "/sites/PublishPractice"  
  2. webAbsoluteUrl: "https://mytest.sharepoint.com/sites/PublishPractice"  
  3. viewId: ""  
  4. webPropertyFlags2: 0  
  5. listId: ""  
  6. listPermsMask: null  
  7. listUrl: ""  
  8. listTitle: null  
  9. listBaseTemplate: -1  
  10. listBaseType: -1  
  11. driveInfo: {}  
  12. vanityUrls: {}  
  13. multiGeoInfo: [{…}]  
  14. viewOnlyExperienceEnabled: false  
  15. blockDownloadsExperienceEnabled: false  
  16. idleSessionSignOutEnabled: false  
  17. activityBasedTimeoutEnabled: false  
  18. activityMonitorModuleLinkEnabled: false  
  19. isUnauthorizedTenant: false  
  20. cdnPrefix: "static.sharepointonline.com/bld"  
  21. cdnBaseUrl: null  
  22. siteAbsoluteUrl: "https://mytest.sharepoint.com/sites/PublishPractice"  
  23. siteId: "{94bba8b7-43e4-4603-8d02-81c220aa2379}"  
  24. showNGSCDialogForSyncOnTS: true  
  25. supportPoundStorePath: true  
  26. supportPercentStorePath: true  
  27. siteSubscriptionId: "b13ba969-995d-4554-bbc3-233141a9cade"  
  28. tenantDisplayName: "mytest"  
  29. isMultiGeoTenant: false  
  30. isMultiGeoODBMode: false  
  31. webDomain: "sharepoint.com"  
  32. IsIEDisabledForItemsScope: false  
  33. isSPO: true  
  34. farmLabel: "IND_201_Content"  
  35. contentDBName: "Content_809195"  
  36. serverRequestPath: "/_layouts/15/workbench.aspx"  
  37. layoutsUrl: "_layouts/15"  
  38. webId: "{d7b179ac-ba57-4f35-b75b-df24bf906b66}"  
  39. webTitle: "PublishPractice"  
  40. webTemplate: "53"  
  41. webTemplateConfiguration: "BLANKINTERNET#0"  
  42. webDescription: ""  
  43. tenantAppVersion: "1"  
  44. isAppWeb: false  
  45. webLogoUrl: "_layouts/15/images/siteicon.png"  
  46. webLanguage: 1033  
  47. webLanguageName: "en-US"  
  48. currentLanguage: 1033  
  49. currentUICultureName: "en-US"  
  50. currentCultureName: "en-US"  
  51. currentCultureLCID: 1033  
  52. env: "prod"  
  53. env2: "prod"  
  54. nid: 12479  
  55. fid: 195205  
  56. serverTime: "2020-04-13T14:29:06.3446430Z"  
  57. siteClientTag: "0$$16.0.20001.12019"  
  58. crossDomainPhotosEnabled: true  
  59. openInClient: false  
  60. webUIVersion: 15  
  61. webPermMasks: {High: 2147483647, Low: 4294967295}  
  62. pageListId: null  
  63. pageItemId: -1  
  64. pagePermsMask: null  
  65. pagePersonalizationScope: 1  
  66. userEmail: "[email protected]"  
  67. userId: 17  
  68. userLoginName: "[email protected]"  
  69. userDisplayName: "Madhan Thurai NC"  
  70. isAnonymousGuestUser: false  
  71. isEmailAuthenticationGuestUser: false  
  72. isExternalGuestUser: false  
  73. isShareByLinkEnabled: false  
  74. FolderAnonymousLinkPermission: 5  
  75. systemUserKey: "i:0h.f|membership|[email protected]"  
  76. alertsEnabled: true  
  77. siteServerRelativeUrl: "/sites/PublishPractice"  
  78. allowSilverlightPrompt: "True"  
  79. themeCacheToken: "/sites/PublishPractice::0:16.0.20001.12019"  
  80. themedCssFolderUrl: null  
  81. themedImageFileNames: null  
  82. modernThemingEnabled: true  
  83. isSiteAdmin: true  
  84. isSiteOwner: true  
  85. ExpFeatures: (63) [-836791292, 1624570697, 620877909, 1736388636, 867936057, -1796975952, 1288360470, 57945375, 273224740, -1793982464, 87445392, -2138906472, 67451592, 545980736, 2159493, 1879736340, 369377650, 830086336, 20206087, 0, 0, 1212153856, -1883956681, -2080757274, -1806289405, -533232128, -115767270, -936371879, -1065350031, 384368717, 1236488464, 192, 0, 1268512236, 1563207295, -64208227, -1172788480, 113054989, -721582382, -1518442702, 561838596, -23925256, 342968415, -951444149, 1076429836, 1747342597, 414355587, -1341637787, 721486338, 599792128, 1164151212, -1308421888, 387990056, 1275278338, 202377090, 405274688, 537925760, 1048716, 1157627916, 0, 0, 0, 0]  
  86. experimentData: "BgABAAAXIHAIAScHBgEBAAB3Bwc"  
  87. experimentDataLookup: []  
  88. killSwitches: {3487BA96-793D-453F-AA6E-5252E0D81ED6: true, 925090C8-8AA6-4C6A-8BFE-1EF2E43038F0: true, F5580BB6-8B44-4428-B490-36B777B4D5F8: true, C50B5771-669C-4853-A87F-1093166E3FE6: true, 00AA590F-D7AC-48DF-B8C9-0546E0AB9803: true, …}  
  89. CorrelationId: "e761489f-b043-0000-38a7-f45d0822bba0"  
  90. hasManageWebPermissions: true  
  91. isNoScriptEnabled: true  
  92. groupId: null  
  93. groupHasHomepage: true  
  94. groupHasQuickLaunchConversationsLink: false  
  95. departmentId: null  
  96. hubSiteId: null  
  97. sensitivityLabel: null  
  98. restrictedToRegion: null  
  99. hasPendingWebTemplateExtension: false  
  100. disableRecommendedItems: false  
  101. isGroupRelatedSite: false  
  102. isArchived: false  
  103. IBSegments: null  
  104. hasAutogeneratedWebLogo: true  
  105. isHubSite: false  
  106. isWebWelcomePage: false  
  107. siteClassification: ""  
  108. hideSyncButtonOnODB: false  
  109. showNGSCDialogForSyncOnODB: false  
  110. sitePagesEnabled: false  
  111. sitePagesFeatureVersion: 0  
  112. featureInfo: {SitePages: {…}, SitePagesResources: {…}, MixedReality: {…}, MixedRealityResources: {…}, RecommendedItems: {…}, …}  
  113. DesignPackageId: "00000000-0000-0000-0000-000000000000"  
  114. groupType: null  
  115. groupColor: "#ca5010"  
  116. siteColor: "#ca5010"  
  117. headerEmphasis: 0  
  118. headerLayout: 0  
  119. searchScope: 0  
  120. searchBoxInNavBar: 1  
  121. searchBoxPlaceholderText: null  
  122. navigationInfo: null  
  123. clientPersistedCacheKey: {CurrentKey: {…}, PreviousKey: {…}}  
  124. guestsEnabled: false  
  125. MenuData: {SettingsData: Array(4), SignOutUrl: "https://mytest.sharepoint.com/sites/PublishPractice/_layouts/15/SignOut.aspx"}  
  126. RecycleBinItemCount: -1  
  127. listItemCount: -1  
  128. PublishingFeatureOn: true  
  129. PreviewFeaturesEnabled: true  
  130. disableAppViews: false  
  131. disableFlows: false  
  132. serverRedirectedUrl: null  
  133. formDigestValue: "0x14FD2B0BD9FA5893C41D8807652990AA6C57E33C559B52EE5CD810FF87C12B1FD6D06577151CA9B4CBA88383B59C8FEF43690A2550225FA745E2F398D01EDA07,13 Apr 2020 14:29:06 -0000"  
  134. IsHomepageModernized: false  
  135. NextStepsFirstRunEnabled: false  
  136. maximumFileSize: 15360  
  137. formDigestTimeoutSeconds: 1800  
  138. canUserCreateMicrosoftForm: false  
  139. canUserCreateVisioDrawing: true  
  140. readOnlyState: null  
  141. isTenantDevSite: false  
  142. preferUserTimeZone: false  
  143. userTimeZoneData: null  
  144. userTime24: false  
  145. userFirstDayOfWeek: null  
  146. webTimeZoneData: {Description: "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", Bias: -330, Id: 23, DaylightBias: -60, DaylightDate: {…}, …}  
  147. webTime24: false  
  148. webFirstDayOfWeek: 0  
  149. aadTenantId: "b13ba969-995d-4554-bbc3-233141a9cade"  
  150. aadUserId: "b4a0dbf7-ad0e-4526-aa7f-b74a291cec9c"  
  151. aadInstanceUrl: "https://login.windows.net"  
  152. aadSessionId: "V2!10032000892FF6FA!13230631649"  
  153. msGraphEndpointUrl: "https://graph.microsoft.com"  
  154. msMruEndpointUrl: "https://ocws.officeapps.live.com"  
  155. allowInfectedDownload: true  
  156. organizationNewsSiteReference: []  
  157. companyPortalReference: null  
  158. knowledgeHubSiteDetails: null  
  159. spfx3rdPartyServicePrincipalId: "f6141ed2-79ff-419a-afa7-01f1b3dfe9b0"  
  160. completenessUrls: null  
  161. socialBarEnabled: true  
  162. substrateOneDriveDisabled: null  
  163. isGroupifyDisabled: false  
  164. Has2019Era: true  
  165. userVoiceForFeedbackEnabled: true  
  166. substrateOneDriveMigrated: null  
  167. userPrincipalName: "[email protected]"  
  168. spfxOBOFlowEnabled: true  
  169. publicCdnBaseUrl: "https://publiccdn.sharepointonline.com"  
  170. SideBySideToken: "16.0.20001.12019"  
  171. farmSettings: {ExternalService_powerappswebhostname: "web.powerapps.com", ExternalService_powerappscreatehostname: "create.powerapps.com", ExternalService_flowhostname: "flow.microsoft.com", ExternalService_flowservicehostname: "service.flow.microsoft.com", ExternalService_popularplatformsenable: "1", …}  
  172. __proto__: Object  
usualy we get pagecontext directly from sharepoint classic page as
  1. _spPageContextInfo  
 pagecontext  from modern page as (Hacky way to get context)
  1. function getmodernpagecontext(url) {      
  2.     var request = new XMLHttpRequest();      
  3.     return new Promise(function(resolve, reject) {      
  4.         request.onreadystatechange = function() {      
  5.             if (request.readyState !== 4) return;      
  6.             if (request.status >= 200 && request.status < 300) {      
  7.                 resolve(request);      
  8.             } else {      
  9.                 reject({      
  10.                     status: request.status,      
  11.                     statusText: request.statusText      
  12.                 });      
  13.             }      
  14.         };      
  15.       
  16.         request.open('GET', url, true);      
  17.         request.setRequestHeader("Content-Type""application/json;charset=utf-8");      
  18.         request.setRequestHeader("ACCEPT""application/json; odata.metadata=verbose");      
  19.         request.setRequestHeader("ODATA-VERSION""4.0");      
  20.         request.send();      
  21.       
  22.     });      
  23. }      
  24.       
  25. //Get the Request location from the browser URL  
  26. var path = location.href.replace(location.search, "") + "?as=json";      
  27.       
  28. //Returns the current user, item, page and context information  
  29. getmodernpagecontext(path).then(function(response) {      
  30.     console.log(JSON.parse(response.response));      
  31. });  
To check other permissions apart from sitecollection admin and tenant admin, import the below module in SPFx
  1. import { SPPermission } from '@microsoft/sp-page-context';  
There are 3 methods to identify permissions, methods only return the boolean value. Before looking through the methods, first, initiate all of the permission objects to get context from the webpart.
  1. let permission = new SPPermission(this.context.pageContext.web.permissions.value);  
hasPermission returns true if the given permission is available for the current user. It holds single value.
  1. const viewpage = permission.hasPermission(SPPermission.viewPages);  
hasAllPermissions returns true if given permissions are available for the current user. If a single permission is not available, it returns false. It holds an array of values.
  1. const fullcontrol = permission.hasAllPermissions(SPPermission.fullMask,SPPermission.viewPages);   
hasAnyPermissions returns true if any one of the given permissions are available for the current user. If a single permission is available, it returns true. It holds an array of values.
  1. const anycontrol = permission.hasAnyPermissions(SPPermission.fullMask,SPPermission.viewPages);  
The available permissions are:
  1. emptyMask - Has no permissions on the Web site. Not available through the user interface.
  2. viewListItems - View items in lists, documents in document libraries, and view Web discussion comments.
  3. addListItems - Add items to lists, add documents to document libraries, and add Web discussion comments.
  4. editListItems - Edit items in lists, edit documents in document libraries, edit Web discussion comments in documents,* and customize web part Pages in document libraries.
  5. deleteListItems - Delete items from a list, documents from a document library, and Web discussion comments in documents.
  6. approveItems - Approve a minor version of a list item or document.
  7. openItems - View the source of documents with server-side file handlers.
  8. viewVersions - View past versions of a list item or document.
  9. deleteVersions - Delete past versions of a list item or document.
  10. cancelCheckout-  Discard or check in a document that is checked out to another user.
  11. managePersonalViews - Create, change and delete personal views of lists.
  12. manageLists - Create and delete lists, add or remove columns in a list, and add or remove public views of a list.
  13. viewFormPages - View forms, views, and application pages, and enumerate lists.
  14. open - Allow users to open a Web site, list, or folder to access items inside that container.
  15. viewPages - View pages in a Web site.
  16. layoutsPage - View the layouts page?
  17. addAndCustomizePages - Add, change, or delete HTML pages or web part Pages, and edit the Web site using a SharePoint* Foundation–compatible editor.
  18. applyThemeAndBorder - Apply a theme or borders to the entire Web site.
  19. applyStyleSheets - Apply a style sheet (.css file) to the Web site.
  20. viewUsageData - View reports on Web site usage.
  21. createSSCSite - Create a Web site using Self-Service Site Creation.
  22. manageSubwebs - Create subsites such as team sites, Meeting Workspace sites, and Document Workspace sites.
  23. createGroups - Create a group of users that can be used anywhere within the site collection.
  24. managePermissions - Create and change permission levels on the Web site and assign permissions to users and groups.
  25. browseDirectories - Enumerate files and folders in a Web site using Microsoft Office SharePoint Designer 2007 and WebDAV interfaces.
  26. browserUserInfo - View information about users of the Web site.
  27. addDelPrivateWebParts - Add or remove personal web parts on a web part Page.
  28. updatePersonalWebParts - Update web parts to display personalized information.
  29. manageWeb - Use features that launch client applications; otherwise, users must work on documents locally and upload changes.
  30. useClientIntegration - Use SOAP, WebDAV, or Microsoft Office SharePoint Designer 2007 interfaces to access the Web site.
  31. useRemoteAPIs - Manage alerts for all users of the Web site.
  32. manageAlerts - Create e-mail alerts.
  33. createAlerts - Allows a user to change his or her user information, such as adding a picture.
  34. editMyUserInfo - Enumerate permissions on the Web site, list, folder, document, or list item.
  35. enumeratePermissions - Has all permissions on the Web site. Not available through the user interface.
  36. fullMask - full control
Let's be practical:
 
Open a command prompt and create a directory for the SPFx solution.
 
md spfx-SpfxPermissions
 
Navigate to the above-created directory.
 
cd spfx-SpfxPermissions
 
Run the Yeoman SharePoint Generator to create the solution.
 
yo @microsoft/sharepoint
 
Solution Name
 
Hit Enter for the default name (spfx-SpfxPermissions in this case) or type in any other name for your solution.
Selected choice - Hit Enter
 
Target for the component
 
Here, we can select the target environment where we are planning to deploy the client web part; i.e., SharePoint Online or SharePoint OnPremise (SharePoint 2016 onwards).
Selected choice - SharePoint Online only (latest).
 
Place of files
 
We may choose to use the same folder or create a subfolder for our solution.
Selected choice - same folder.
 
Deployment option
 
Selecting Y will allow the app to be deployed instantly to all sites and be accessible everywhere.
Selected choice - N (install on each site explicitly).
 
Permissions to access web APIs
 
Choose if the components in the solution require permission to access web APIs that are unique and not shared with other components in the tenant.
Selected choice - N (solution contains unique permissions)
 
Type of client-side component to create
 
We can choose to create a client-side web part or an extension. Choose the web part option.
Selected choice - WebPart
 
Web part name
 
Hit Enter to select the default name or type in any other name.
Selected choice - SpfxListView
 
Web part description
 
Hit Enter to select the default description or type in any other value.
 
Framework to use
 
Select any JavaScript framework to develop the component. Available choices are - No JavaScript Framework, React, and Knockout.
Selected choice - React
 
The Yeoman generator will perform a scaffolding process to generate the solution. The scaffolding process will take a significant amount of time.
 
Once the scaffolding process is completed, lock down the version of project dependencies by running the below command,
 
npm shrinkwrap
 
In SpfxPermissionsWebPart.ts
  1. public render(): void {  
  2.   const element: React.ReactElement<ISpfxPermissionsProps> = React.createElement(  
  3.     SpfxPermissions,  
  4.     {  
  5.       description: this.properties.description,  
  6.       context: this.context  
  7.     }  
  8.   );  
  9.   
  10.   ReactDom.render(element, this.domElement);  
  11. }  
In SpfxPermissions.tsx
  1. import * as React from 'react';  
  2. import { ISpfxPermissionsProps } from './ISpfxPermissionsProps';  
  3. import { SPPermission } from '@microsoft/sp-page-context';  
  4. interface Permissionstate {      
  5.   noadmin: boolean;  
  6.   siteadmin:boolean;  
  7.   tenantadmin:boolean;    
  8. }    
  9. export default class SpfxPermissions extends React.Component<ISpfxPermissionsProps, Permissionstate> {  
  10.   constructor(props: ISpfxPermissionsProps) {    
  11.     super(props);     
  12.     this.state = {    
  13.       noadmin: false,  
  14.       siteadmin:false,  
  15.       tenantadmin:false  
  16.     };    
  17.   }  
  18.   public componentDidMount(){  
  19.     this.UserSitePermission();  
  20.   }  
  21.   
  22.   private UserSitePermission() {  
  23.     console.log(this.props.context.pageContext.web.permissions);  
  24.     console.log(this.props.context.pageContext.legacyPageContext);  

  25.   let sitecoladmin:boolean=this.props.context.pageContext.legacyPageContext.isSiteAdmin;  
  26.   let siteowner:boolean=this.props.context.pageContext.legacyPageContext['isSiteOwner'];  
  27.   
  28.     let permission = new SPPermission(this.props.context.pageContext.web.permissions.value);  
  29.   
  30.     let canEdit = permission.hasPermission(SPPermission.manageWeb);  
  31.     const fullcontrol = permission.hasAllPermissions(SPPermission.fullMask);  
  32.     const anycontrol = permission.hasAnyPermissions(SPPermission.fullMask);  
  33.     const viewpage = permission.hasPermission(SPPermission.viewPages);  
  34.     const nopermision = permission.hasPermission(SPPermission.emptyMask);  
  35.     this.setState({   
  36.       noadmin: nopermision,  
  37.   siteadmin:sitecoladmin,  
  38.   tenantadmin:siteowner  
  39.     });  
  40.   
  41.   }  
  42.   public render(): React.ReactElement<ISpfxPermissionsProps> {  
  43.       
  44.   if(this.state.siteadmin === true) {  
  45.     return (  
  46.       <div >  
  47.  I am site collection admin  
  48.       </div>  
  49.     );}  
  50.     else if(this.state.tenantadmin === true) {  
  51.       return (  
  52.         <div >  
  53.    I am Tenent admin  
  54.         </div>  
  55.       );}  
  56.       else  {  
  57.         return (  
  58.           <div >  
  59.      I am not an Administrator  
  60.           </div>  
  61.         );}  
  62.   
  63. }}  
In ISpfxPermissionsProps.ts
  1. import { WebPartContext } from "@microsoft/sp-webpart-base";   
  2. export interface ISpfxPermissionsProps {  
  3.   description: string;  
  4.   context:WebPartContext;  
  5. }  
Expected Output
 

Conclusion

 
We learned how to hide/show webpart based on user permissions in SPFx. I hope this helps someone. Happy coding :)