Аутентификация в веб-приложении или свой ApplicationContext

Когда пишешь веб-приложение, стандартная проблема, которая возникает - это как хранить и доставать свойства текущего зарегистрированного пользователя в различных уровнях приложения (см. мой пост http://relib.com/blogs/rulez/archive/2005/07/28/2517.aspx).

Так как для веб-приложений характерно хранить подобные данные в сессии, а для windows или тестов - в статичной переменной, то получается, что необходимо каким-либо образом разделить логику получения этих данных. Тут на помощь приходит механизм контекстов. В посте http://relib.com/blogs/rulez/archive/2005/07/28/2517.aspx были описаны различные уровни приложения. В этом посте будет описано, как организовать Application service layer.

Итак, нам понадобится: ASP.NET-проект (назовем его WebUI), проекты Class library - BusinessObjects, DAO, BusinessServices, ApplicationServices.

 

1 шаг - определим класс UserCredentials в BusinessObjects:

 

Public Class UserCredentials

 

    Private _userId As String

    Private _password As String

 

    Public Property UserId() As String

        Get

            Return _userId

        End Get

        Set(ByVal Value As String)

            _userId = Value

        End Set

    End Property

 

    Public Property Password() As String

        Get

            Return _password

        End Get

        Set(ByVal Value As String)

            _password = Value

        End Set

    End Property

End Class

 

Класс UserCredentials будет использоваться для хранения информации о пользователе. В нашем случае это просто логин и пароль, хотя сюда можно добавить и ФИО, адрес, e-mail и любую другую информацию.

 

2 шагв DAO нам понадобится класс UserDAO

 

Public Class UserDAO

 

    Public Shared Function GetUser(ByVal userId As String) As UserCredentials

        If userId = "Vitaly" Then

            Dim user As New UserCredentials

            user.UserId = "Vitaly"

            user.Password = "1"

 

            Return user

        End If

    End Function

 

    Public Shared Function CheckUser(ByVal userId As String, ByVal password As String) As Boolean

        If userId = "Vitaly" And password = "1" Then

            Return True

        Else

            Return False

        End If

    End Function

End Class

 

Вообще говоря, метод GetUser должен брать данные из базы, а CheckUser проверять логин и пароль по базе.

 

3 шаг – в Application Service нам понадобятся классы:

 

Public Interface IApplicationContext

 

    Function GetCurrentUser() As UserCredentials

 

    Function GetCurrentIdentity() As IIdentity

End Interface

Public Class ApplicationContextFactory

 

    Private Shared _context As IApplicationContext

 

    Private Sub New()

    End Sub

 

    Public Shared Property Context() As IApplicationContext

        Get

            Return _context

        End Get

        Set(ByVal Value As IApplicationContext)

            _context = Value

        End Set

    End Property

End Class

 

Это и есть классы, необходимые для контекста. Теперь пишем реализацию контекста в Web приложении:

 

Public Class WebApplicationContext

    Implements IApplicationContext

 

    Private _application As HttpApplication

 

    Public Property Application() As HttpApplication

        Get

            Return _application

        End Get

        Set(ByVal Value As HttpApplication)

            _application = Value

        End Set

    End Property

 

    Public Function GetCurrentIdentity() As IIdentity Implements IApplicationContext.GetCurrentIdentity

        Return _application.Context.User.Identity

    End Function

 

    Public Function GetCurrentUser() As UserCredentials Implements IApplicationContext.GetCurrentUser

        If Not (TypeOf _application.Context.Session("UserCredentials") Is UserCredentials) Then

            If _application.Context.User.Identity.Name <> String.Empty Then

                'set user to session

                _application.Context.Session("UserCredentials") = _

                    UserDAO.GetUser(_application.Context.User.Identity.Name)

            End If

        End If

 

        Return _application.Context.Session("UserCredentials")

    End Function

End Class

 

Для веб-приложения мы получаем данные из сессии. Для примера, для тестового приложения можно сделать такую реализацию:

 

Public Class TestApplicationContext

    Implements IApplicationContext

 

    Public Function GetCurrentIdentity() As IIdentity Implements IApplicationContext.GetCurrentIdentity

        Return System.Security.Principal.WindowsIdentity.GetCurrent

    End Function

 

    Public Function GetCurrentUser() As UserCredentials Implements IApplicationContext.GetCurrentUser

        Dim user As New UserCredentials

        user.UserId = "TestUser"

        user.Password = "TestPassword"

 

        Return user

    End Function

End Class

 

Далее, чтобы установить контекст пишем свой модуль для веб-приложения и подключаем его в web.config:

<httpModules>

<add name="WebApplicationModule" type="AspNetCredentialsSampleUI.WebApplicationModule, WebUI " />

</httpModules>

 

Сам модуль:

 

Public Class WebApplicationModule

    Implements IHttpModule

 

    Private WithEvents _context As HttpApplication

 

    Public Sub Dispose() Implements IHttpModule.Dispose

        _context.Dispose()

    End Sub

 

    Public Sub Init(ByVal context As HttpApplication) Implements IHttpModule.Init

        _context = context

    End Sub

 

    Private Sub OnAcquireRequestState(ByVal sender As Object, ByVal e As EventArgs) Handles _context.AcquireRequestState

        Dim appContext As New WebApplicationContext

        appContext.Application = _context

 

        ApplicationContextFactory.Context = appContext

 

        _context.Context.Session("UserCredentials") = _

            UserDAO.GetUser(_context.Context.User.Identity.Name)

    End Sub

 

End Class