Аутентификация в веб-приложении или свой 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