Back to Devexpress

IWebDocumentViewerAuthorizationService Interface

xtrareports-devexpress-dot-xtrareports-dot-web-dot-webdocumentviewer-75aaa9d5.md

latest23.8 KB
Original Source

IWebDocumentViewerAuthorizationService Interface

Implements custom authorization to restrict access to reports and generated documents in a web reporting application.

Namespace : DevExpress.XtraReports.Web.WebDocumentViewer

Assembly : DevExpress.XtraReports.v25.2.Web.dll

NuGet Package : DevExpress.Web.Reporting.Common

Declaration

csharp
public interface IWebDocumentViewerAuthorizationService
vb
Public Interface IWebDocumentViewerAuthorizationService

Remarks

General Information

The Document Viewer queries the IWebDocumentViewerAuthorizationService service when the control performs the following actions:

  • Operations that read a report from the internal storage
  • Operations that create a document or render a document page
  • Export and print operations
  • Search operations
  • Operations that request data from a document, such as processing the contents of the editable fields or building a document map.

For access control purposes, all operations can be classified by the object that the document viewer processes in a particular operation. The objects are:

  • Reports
  • Documents
  • Document export results.

Tip

Review the following topic for more information on the Document Viewer operations: Document Viewer Lifecycle

Implementation

You should add a custom logic to the IWebDocumentViewerAuthorizationService methods to determine whether the current user is allowed to perform the operation. The methods are grouped by objects that require authorized access.

CanCreateReport Verifies whether the user can create a report in the viewer’s internal storage. If this method returns false , the Document Viewer fails on initialization. Implement this method to restrict users from previewing a report in the Report Designer.CanReadReportVerifies whether the user can perform an operation with the report. The method is called when the Document Viewer requests report parameters, their lookup values, initiates document creation or a drill-through operation. You can determine that the initiator of the operation is the same user who opened the report.CanReleaseReportPrevents unauthorized disposal of the report when performed by a person who is not a report creator, or when the report is shared by several users, and the current user is not allowed to dispose of the report.CanCreateDocumentVerifies whether the user can create a document in the viewer’s internal storage. You can use this method to restrict the number of report creation operations the user initiates.CanReadDocumentAllows you to prevent unauthorized operations with a document. Refer to the API method help topic for the list of operations.CanReleaseDocument Prevents unauthorized disposal of the document from the viewer’s cache and internal storage.

When you implement these methods, you need information about the current user, about the report that the user opens, what parameters are applied, what are the ids assigned to the report, the document and to the document generated in an asynchronous export operation. Implement the WebDocumentViewerOperationLogger interface to gather all the required information.

Examples

ASP.NET MVC Example

View Example: Implement User Authorization

The following code is a custom interface implementation that allows authorized users to view the report in the Document Viewer. A custom WebDocumentViewerOperationLogger service populates dictionaries with the user id, report id, document id and asynchronous operation id. The IWebDocumentViewerAuthorizationService controls access to reports and documents, the IExportingAuthorizationService controls access to the asynchronously exported document.

csharp
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using System.Collections.Concurrent;
using System.Web;
using System;
using DevExpress.XtraPrinting;
using DevExpress.XtraReports.Web.ClientControls;

namespace AuthorizationService.Services {
    public class OperationLogger: WebDocumentViewerOperationLogger, 
        IWebDocumentViewerAuthorizationService, 
        IExportingAuthorizationService
    {
        public override void ReportOpening(string reportId, string documentId, XtraReport report) 
        {
            if (HttpContext.Current.Session == null) {
                return;
            }
            SaveUsedEntityId(Constants.ReportDictionaryName, reportId);
            SaveUsedEntityId(Constants.DocumentDictionaryName, documentId);
        }

        public override void BuildStarted(string reportId, string documentId, 
            ReportBuildProperties buildProperties) 
        {
            SaveUsedEntityId(Constants.ReportDictionaryName, reportId);
            SaveUsedEntityId(Constants.DocumentDictionaryName, documentId);
        }

        public override ExportedDocument ExportDocumentStarting(string documentId, 
            string asyncExportOperationId, string format, ExportOptions options, 
            PrintingSystemBase printingSystem, Func<ExportedDocument> doExportSynchronously) 
        {
            SaveUsedEntityId(Constants.ExportedDocumentDictionaryName, asyncExportOperationId);
            return base.ExportDocumentStarting(documentId, asyncExportOperationId, format, options, 
                printingSystem, doExportSynchronously);
        }

        public override void ReleaseDocument(string documentId) {

        }

        bool IWebDocumentViewerAuthorizationService.CanCreateDocument() {
            return CheckUserAuthorized();
        }

        bool IWebDocumentViewerAuthorizationService.CanCreateReport() {
            return CheckUserAuthorized();
        }

        bool IWebDocumentViewerAuthorizationService.CanReadDocument(string documentId) {
            return CheckEntityAvailability(Constants.DocumentDictionaryName, documentId);
        }

        bool IWebDocumentViewerAuthorizationService.CanReadReport(string reportId) {
            return CheckEntityAvailability(Constants.ReportDictionaryName, reportId);
        }

        bool IWebDocumentViewerAuthorizationService.CanReleaseDocument(string documentId) {
            return CheckEntityAvailability(Constants.DocumentDictionaryName, documentId);
        }

        bool IWebDocumentViewerAuthorizationService.CanReleaseReport(string reportId) {
            return CheckEntityAvailability(Constants.ReportDictionaryName, reportId);
        }

        public bool CanReadExportedDocument(string exportDocumentId) {
            return CheckEntityAvailability(Constants.ExportedDocumentDictionaryName, exportDocumentId);
        }

        bool CheckUserAuthorized() {
            var user = HttpContext.Current.User;
            if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
            {
                return false;
            }
            return true;
        }

        void SaveUsedEntityId(string dictionaryName, string id) {
            if (string.IsNullOrEmpty(id))
                return;

            ConcurrentDictionary<string, bool> dictionary = null;
            lock (HttpContext.Current.Session.SyncRoot) {
                if (HttpContext.Current.Session[dictionaryName] == null)
                     HttpContext.Current.Session[dictionaryName] = dictionary 
                        = new ConcurrentDictionary<string, bool>();
            }
            if (dictionary == null)
                dictionary = ((ConcurrentDictionary<string, bool>)HttpContext.Current.
                    Session[dictionaryName]);
            dictionary.AddOrUpdate(id, false, (_1, _2) => false);
        }

        bool CheckEntityAvailability(string dictionaryName, string id) {
            if (string.IsNullOrEmpty(id) || !CheckUserAuthorized())
                return false;

            lock (HttpContext.Current.Session.SyncRoot) {
                if (HttpContext.Current.Session[dictionaryName] == null)
                    return false;
            }
            return 
            ((ConcurrentDictionary<string, bool>)HttpContext.Current.
                Session[dictionaryName]).ContainsKey(id);
        }

        void DisposeEntityRequested(string dictionaryName, string id) {
            if (string.IsNullOrEmpty(id))
                return;
            lock (HttpContext.Current.Session.SyncRoot) {
                if (HttpContext.Current.Session[dictionaryName] == null)
                    return;
            }
            ((ConcurrentDictionary<string, bool>)HttpContext.Current.
                Session[dictionaryName]).AddOrUpdate(id, true, (_1, _2) => true);
        }
    }
}
vb
Imports DevExpress.XtraReports.Web.WebDocumentViewer
Imports System.Collections.Concurrent
Imports System.Web
Imports System
Imports DevExpress.XtraReports.UI
Imports DevExpress.XtraPrinting
Imports DevExpress.XtraReports.Web.ClientControls

Namespace AuthorizationService.Services
    Public Class OperationLogger
        Inherits WebDocumentViewerOperationLogger
        Implements IWebDocumentViewerAuthorizationService, IExportingAuthorizationService

#Region "WebDocumentViewerOperationLogger"
        Public Overrides Sub ReportOpening(ByVal reportId As String, ByVal documentId As String,
                                           ByVal report As XtraReport)
            If HttpContext.Current.Session Is Nothing Then
                Return
            End If
            SaveUsedEntityId(Constants.ReportDictionaryName, reportId)
            SaveUsedEntityId(Constants.DocumentDictionaryName, documentId)
        End Sub

        Public Overrides Sub BuildStarted(ByVal reportId As String, ByVal documentId As String,
                                          ByVal buildProperties As ReportBuildProperties)
            SaveUsedEntityId(Constants.ReportDictionaryName, reportId)
            SaveUsedEntityId(Constants.DocumentDictionaryName, documentId)
        End Sub

        Public Overrides Function ExportDocumentStarting(ByVal documentId As String,
                            ByVal asyncExportOperationId As String,
                            ByVal format As String,
                            ByVal options As ExportOptions,
                            ByVal printingSystem As PrintingSystemBase,
                            ByVal doExportSynchronously As Func(Of ExportedDocument)) As ExportedDocument
            SaveUsedEntityId(Constants.ExportedDocumentDictionaryName, asyncExportOperationId)
            Return MyBase.ExportDocumentStarting(documentId, asyncExportOperationId, format,
                                                 options, printingSystem, doExportSynchronously)
        End Function

        Public Overrides Sub ReleaseDocument(ByVal documentId As String)

        End Sub
#End Region

#Region "IWebDocumentViewerAuthorizationService"
        Private Function IWebDocumentViewerAuthorizationService_CanCreateDocument() As Boolean _
            Implements IWebDocumentViewerAuthorizationService.CanCreateDocument
            Return CheckUserAuthorized()
        End Function

        Private Function IWebDocumentViewerAuthorizationService_CanCreateReport() As Boolean _
            Implements IWebDocumentViewerAuthorizationService.CanCreateReport
            Return CheckUserAuthorized()
        End Function

        Private Function IWebDocumentViewerAuthorizationService_CanReadDocument(ByVal documentId As String) _
            As Boolean _
            Implements IWebDocumentViewerAuthorizationService.CanReadDocument
            Return CheckEntityAvailability(Constants.DocumentDictionaryName, documentId)
        End Function

        Private Function IWebDocumentViewerAuthorizationService_CanReadReport(ByVal reportId As String) _
            As Boolean _
            Implements IWebDocumentViewerAuthorizationService.CanReadReport
            Return CheckEntityAvailability(Constants.ReportDictionaryName, reportId)
        End Function

        Private Function IWebDocumentViewerAuthorizationService_CanReleaseDocument(ByVal documentId As String) _
            As Boolean _
            Implements IWebDocumentViewerAuthorizationService.CanReleaseDocument
            Return CheckEntityAvailability(Constants.DocumentDictionaryName, documentId)
        End Function

        Private Function IWebDocumentViewerAuthorizationService_CanReleaseReport(ByVal reportId As String) _
            As Boolean _
            Implements IWebDocumentViewerAuthorizationService.CanReleaseReport
            Return CheckEntityAvailability(Constants.ReportDictionaryName, reportId)
        End Function

        Public Function CanReadExportedDocument(ByVal exportDocumentId As String) As Boolean _
            Implements IExportingAuthorizationService.CanReadExportedDocument
            Return CheckEntityAvailability(Constants.ExportedDocumentDictionaryName, exportDocumentId)
        End Function
#End Region ' IWebDocumentViewerAuthorizationService, IExportingAuthorizationService

        Private Function CheckUserAuthorized() As Boolean
            Dim user = HttpContext.Current.User
            If user Is Nothing OrElse user.Identity Is Nothing OrElse Not user.Identity.IsAuthenticated Then
                Return False
            End If
            Return True
        End Function

        Private Sub SaveUsedEntityId(ByVal dictionaryName As String, ByVal id As String)
            If String.IsNullOrEmpty(id) Then
                Return
            End If

            Dim dictionary As ConcurrentDictionary(Of String, Boolean) = Nothing
            SyncLock HttpContext.Current.Session.SyncRoot
                If HttpContext.Current.Session(dictionaryName) Is Nothing Then
                     dictionary = New ConcurrentDictionary(Of String, Boolean)()
                     HttpContext.Current.Session(dictionaryName) = dictionary
                End If
            End SyncLock
            If dictionary Is Nothing Then
                dictionary = (DirectCast(HttpContext.Current.Session(dictionaryName),
                    ConcurrentDictionary(Of String, Boolean)))
            End If
            dictionary.AddOrUpdate(id, False, Function(_1, _2) False)
        End Sub

        Private Function CheckEntityAvailability(ByVal dictionaryName As String,
                                                 ByVal id As String) As Boolean
            If String.IsNullOrEmpty(id) OrElse Not CheckUserAuthorized() Then
                Return False
            End If

            SyncLock HttpContext.Current.Session.SyncRoot
                If HttpContext.Current.Session(dictionaryName) Is Nothing Then
                    Return False
                End If
            End SyncLock
            Return DirectCast(HttpContext.Current.Session(dictionaryName),
                ConcurrentDictionary(Of String, Boolean)).ContainsKey(id)
        End Function

        Private Sub DisposeEntityRequested(ByVal dictionaryName As String, ByVal id As String)
            If String.IsNullOrEmpty(id) Then
                Return
            End If
            SyncLock HttpContext.Current.Session.SyncRoot
                If HttpContext.Current.Session(dictionaryName) Is Nothing Then
                    Return
                End If
            End SyncLock
            DirectCast(HttpContext.Current.Session(dictionaryName),
                ConcurrentDictionary(Of String, Boolean)).AddOrUpdate(id, True, Function(_1, _2) True)
        End Sub
    End Class
End Namespace

Register the service on application startup:

csharp
protected void Application_Start() {
...
    DefaultWebDocumentViewerContainer.Register<IExportingAuthorizationService, Services.OperationLogger>();
    DefaultWebDocumentViewerContainer.Register<WebDocumentViewerOperationLogger, Services.OperationLogger>();
    DefaultWebDocumentViewerContainer.Register<IWebDocumentViewerAuthorizationService, Services.OperationLogger>();
    ...
}
vb
Protected Sub Application_Start()
...
    DefaultWebDocumentViewerContainer.Register(Of IExportingAuthorizationService, Services.OperationLogger)()
    DefaultWebDocumentViewerContainer.Register(Of WebDocumentViewerOperationLogger, Services.OperationLogger)()
    DefaultWebDocumentViewerContainer.Register(Of IWebDocumentViewerAuthorizationService, Services.OperationLogger)()
    ...
End Sub

ASP.NET Core Example

View Example: Implement User Authorization

The following code is a custom interface implementation that allows authorized users to view the report in the Document Viewer. A custom WebDocumentViewerOperationLogger service populates dictionaries with the user id, report id, document id and asynchronous operation id. The IWebDocumentViewerAuthorizationService controls access to reports and documents, the IExportingAuthorizationService controls access to the asynchronously exported document.

csharp
using System;
using System.Collections.Concurrent;
using DevExpress.XtraPrinting;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.ClientControls;
using DevExpress.XtraReports.Web.WebDocumentViewer;

namespace AspNetCore.Reporting.Common.Services.Reporting {
    class DocumentViewerAuthorizationService : 
        WebDocumentViewerOperationLogger, 
        IWebDocumentViewerAuthorizationService, 
        IExportingAuthorizationService 
    {
        static ConcurrentDictionary<string, string> DocumentIdOwnerMap { get; } = 
            new ConcurrentDictionary<string, string>();
        static ConcurrentDictionary<string, string> ExportedDocumentIdOwnerMap { get; } = 
            new ConcurrentDictionary<string, string>();
        static ConcurrentDictionary<string, string> ReportIdOwnerMap { get; } = 
            new ConcurrentDictionary<string, string>();

        IAuthenticatiedUserService UserService { get; }

        public DocumentViewerAuthorizationService(IAuthenticatiedUserService userService) 
        {
            UserService = userService ?? throw new ArgumentNullException(nameof(userService));
        }

        public override void ReportOpening(string reportId, string documentId, XtraReport report) 
        {
            MapIdentifiersToUser(UserService.GetCurrentUserId(), documentId, reportId, null);
            base.ReportOpening(reportId, documentId, report);
        }

        public override void BuildStarted(string reportId, string documentId, 
            ReportBuildProperties buildProperties) 
        {
            MapIdentifiersToUser(UserService.GetCurrentUserId(), documentId, reportId, null);
            base.BuildStarted(reportId, documentId, buildProperties);
        }

        public override ExportedDocument ExportDocumentStarting(string documentId, 
            string asyncExportOperationId, string format, ExportOptions options, 
            PrintingSystemBase printingSystem, Func<ExportedDocument> doExportSynchronously) 
        {
            MapIdentifiersToUser(UserService.GetCurrentUserId(), null, null, asyncExportOperationId);
            return base.ExportDocumentStarting(documentId, 
                asyncExportOperationId, format, options, printingSystem, doExportSynchronously);
        }

        void MapIdentifiersToUser(string userId, string documentId, 
            string reportId, string exportedDocumentId) 
        {
            if(!string.IsNullOrEmpty(exportedDocumentId))
                ExportedDocumentIdOwnerMap.TryAdd(exportedDocumentId, userId);

            if(!string.IsNullOrEmpty(documentId)) 
                DocumentIdOwnerMap.TryAdd(documentId, userId);

            if(!string.IsNullOrEmpty(reportId)) 
                ReportIdOwnerMap.TryAdd(reportId, userId);

        }

        #region IWebDocumentViewerAuthorizationService
        public bool CanCreateDocument() 
        {
            return true;
        }

        public bool CanCreateReport() 
        {
            return true;
        }

        public bool CanReadDocument(string documentId) 
        {
            return DocumentIdOwnerMap.TryGetValue(documentId, out var ownerId) 
                && ownerId == UserService.GetCurrentUserId();
        }

        public bool CanReadReport(string reportId) 
        {
            return ReportIdOwnerMap.TryGetValue(reportId, out var ownerId) 
                && ownerId == UserService.GetCurrentUserId();
        }

        public bool CanReleaseDocument(string documentId) 
        {
            return true;
        }

        public bool CanReleaseReport(string reportId) 
        {
            return true;
        }

        public bool CanReadExportedDocument(string exportedDocumentId) 
        {
            return ExportedDocumentIdOwnerMap.TryGetValue(exportedDocumentId, out var ownerId) 
                && ownerId == UserService.GetCurrentUserId();
        }
        #endregion
    }
}

Register the service on application start. The following code registers three services which implement access check in our example:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<IWebDocumentViewerAuthorizationService, DocumentViewerAuthorizationService>();
builder.Services.AddScoped<WebDocumentViewerOperationLogger, DocumentViewerAuthorizationService>();
builder.Services.AddScoped<IExportingAuthorizationService, DocumentViewerAuthorizationService>();

var app = builder.Build();

See Also

IWebDocumentViewerAuthorizationService Members

WebDocumentViewerOperationLogger

IExportingAuthorizationService

Web Reporting Application Security

DevExpress.XtraReports.Web.WebDocumentViewer Namespace