This is actually a very exciting topic for me as I have always struggled with ways to secure the customizations I provided to users using Visualforce based on their access to data in the system. So let me first provide some background on when this issue comes up and then we can talk about the latest addition to Salesforce.com as of Spring ’11 (version 24.0) that makes solving for this trivial.
A typical use-case for me is to override either the detail page or edit page of an existing standard page. Now in some cases, at least for detail page overrides, the
apex:detail tag is invaluable in displaying the page layout and allowing me to enhance the interface a bit. But in some cases I just need to take over completely and it can be difficult to determine if a user will have access to click the edit button. I have solved for this in the past by checking the role or profile, peaking at the account shares, or just allowing Salesforce to report the "Insufficient Privileges" error when the user clicks edit.
I should probably also mention that using the Describe Schema methods you can check if a user has access to an object but that only solves for cases when the user doesn't have access to the object, it doesn't account for a user’s access level at the record level.
While the solutions above did work, they just didn't provide the best user experience. After all, why show an edit button if the user can't edit a record. Alternatively, checking profiles and shares affect page load times, is inefficient and just increases the complexity of your code.
The solution that was released in Spring ’11 (version 24.0) solves for this in a very elegant way. Salesforce implemented a read-only object that you can use to query whether a user has access to a record. The object is appropriately called UserRecordAccess and provides a comprehensive summary of a user’s given access to a particular record. Because it is an object that is designed to be queried, it is very simple to plugin the user’s id and a record id (or set of record ids) and get a result.
Here is a link to the documentation for this feature:
It is a really simple object to use as long as you already know how to perform queries and for those just looking for a quick example of the syntax here is how to use it:
[SELECT RecordId , HasReadAccess , HasEditAccess , HasDeleteAccess FROM UserRecordAccess WHERE UserId=:UserInfo.getUserId() AND RecordId =: Account.Id];
There are some limitations to this object that you should be aware of. Most are trivial and understandable as you can read about at the link provided above, however, I would like to highlight one particular limitation and that is that you can only request up to 200 records.
It’s an understandable limitation but important to remember when working with a list of records. This is a scenario that is more likely to be an issue when providing mass edit functionality and the best way to solve for that would be to implement paging, filtering, and/or limit the number of records displayed to 200 or less.
I have already been able to use this feature in a couple of scenarios and it has saved me a great deal of time and pain trying to account for all of the various ways a user can gain or lose access to a record.