Избавляемся от базы стандартных пользователей ASP.NET на MS SQL - пример ASP.NET сайта на MySQL.
MS SQL является тяжелейшим обременителем технологии ASP.NET. Я многократно разъяснял причины этого - повторятся не будем, интересующихся отсылаю к страничкам - Используем MySQL вместо MS SQL в проектах на ASP.NET, Программирование в SQL SERVER, Осторожно Microsoft. Вероятно, наличие именно этого безумно дорогого продукта в пакете технологий ASP.NET и приводит к тому, что эта неплохая в целом технология занимает всего 0,4% рынка Web-технологий.
Поэтому очевидно, что все что может интересовать на практике ASP.NET-программистов - это снижение стоимости их законченных ASP.NET-сайтов для конечных потребителей. В первую очередь путем избавления от немыслимо дорогого MS SQL-сервера и от Windows конечно тоже. Тем более конкурирующие бесплатные продукты не хуже, а лучше билогейтсовских. Просто их бренды не настолько раскрученные и их не навязывают детям на уроках дэз-информатики в школе. Да и навязывать и раскручивать бесплатные продукты особо некому - не то что шестерки Билла Гейтса с чемоданами баксов, проталкивающие Windows.
Собственно же ASP.NET-программирование c СУБД MySQL не требует хитростей типа сохранения коннекта (как это требуется в PostgreSQL - Этюды на ASP.NET. Пример сайта на СУБД PostgreSQL) - техника ASP-NET программирования с MySQL ничем не отличается от техники программирования с MS SQL. Поэтому я сделал этот пример не просто примером сайта с MySQL - а примером ASP.NET-сайта с отказом от стандартных пользователей ASP.NET, обычно устанавливаемых в MS SQL.
Описанное здесь решение является сильно упрощенной реализацией моего популярного коммерческого решения для управления ASP.NET-пользователями, описанного здесь AspNet_UserManager - компонент сайта для управления пользователями. Здесь, как вы понимаете все правильно - для платного микрософтовского MS SQL Server у меня рапространяется платное управления ASP.NET-пользователями, а для бесплатного MySQL аналогичное по функционалу решение - полностью OpenSource. Кроме того, платное решение включает в себя мою фирменную и пока никем не взломанную капчу и представляет собой просто библитеку, которую надо положить в BIN-директорию проекта и просто оплатить, а описанный на этой страничке OpenSource-проект - это конструктор, из которого вы сами должны выделить в свой проект нужные вам фрагменты кода.
Еще один пример использования MySQL вместо MS SQL вы можете посмотреть у меня на страничке Как сделать SOAP/WSDL-вебсервис на ASP.NET/MONO для вызова его из FLEX.
Итак, если призадуматься, то использование стандартных ASP.NET-пользователей (устанавливаемых обычно мастером aspnet_regsql.exe) непонятно что приносит больше - пользы или вреда:
- Трудно сконфигурировать многочисленные параметры Web-конфига, которым управляются стандартные пользователи. Это сотни параметров, вникать в которые никому не хочется. В результате на практике (при эксплуатации сайта) возникают непонятные проблемы в непонятном месте от того, что ASP.NET-девелоперы проявляют неуважение к своим потребителями и нагружают эксплуатационные службы горой каких-то плохоуправляемых микрософтовских помоев. Например юзер ввел четыре раза неверный пароль и почему-то заблокировался. Чтобы понять как его разблокировать - надо не только сделать сложные ручные манипуляции с базой, но и правильно поправить умалчиваемые настройки в конфиге. Но все дело в том, что там СОТНИ настроек. И ими все равное нельзя получить все, что хочешь. Получается, что ты пользуешься неуправляемой пирамидой чужого и ненужного кода. И делаешь это фактически из хулиганских побуждений - ибо всю эту пирамиду можно легко заменить десятью строчками собственного кода, которые будут перед глазами суппорта и будут делать конкретно то, что требуется в данном проекте.
- Стандартные ASP-NET профили сделаны вообще адски. С нарушением всех мыслимых законов нормализации данных. Похоже микрософтовские индусы просто не слышали о нормализации данных. Отбирать что-то по данным профилям на уровне SQL можно только собственными CLR-сборками. Что еще глубже затягивает вас в пучину микрософтовских технологий, ибо те же сборки невозможно сделать на MySQL - только на MS SQL. Который работает только на Windows. Подробнее эту тему с профилями я осветил здесь - Сборка для работы с данными стандартных ASP.NET-профилей на уровне SQL.
- Микрософтовские индусы провели границу между стандартным повторяющимся из-проекта в проект кодом и меняющимся кодом не там, где это нужно. Эта граница выглядит как пакт Молотова-Рибентропа, проведенный по Волге. Они не включили в повторяющийся код активацию логина с использованием указанного почтового адреса пользователя - зато включили в стандартный код горы всякой ерунды, (параметры управления которой вы можете видеть в web.config) и кучу еще более глупых web-контролов. В описанном ниже решении я проведу границу между стандартным, повторяющимся из проекта в проект кодом иначе, чем его проводит микрософт.
Итак, вы выполнили инсталяцию MySQL, установили коннектор к MySQL - как это описано на этой моей страничке Используем MySQL вместо MS SQL в проектах на ASP.NET. Скопировали MySql.Data.dll в папку BIN проекта и лучше даже прописали его в Mashine.config (это должен автоматически сделать инсталятор коннектора).
MySQL Connector Net состоит с точки зрения .NET-программиста из четырех компонентов:
- MySql.Data.dll - доступ к MySQL из .NET и ASP.NET
- MySql.Data.Entity.dll - работа с LINQ
- MySql.Data.CF.dll - общее определение типов
- MySql.Web.dll - работа с профилями и встроенными пользователями ASP.NET
Последняя сборка как раз и предназначена для тех, кто не хотел бы отказываться от стандартных пользователей в базах aspnet_users, aspnet_membership, считывания/записи пользователей из этих баз с помощью заведомо сделанной микрософтом обвязки Membership.GetUser/Membership.Save. А также сохранения/загрузки профиля ASP.NET пользователя с помощью встроенных микрософтовских классов UserProfile.GetProfile и UserProfile.Save.
Теперь посмотрим, как программистам, травмированным Microsoft Sql Server, создать юзера release для работы сайта, назначить ему нужные права, создать базу release и необходимую структуру данных в ней. Те, чей мозг не травмирован Microsoft SQL Server - могут этот раздел пропустить.
При инсталяции MySQL вы указывали пароль MySQL-юзера root и возможно ставили галку анонимного доступа к MySQL. Теперь (последовательно) приконнектитесь к вашему MySQL из под root, создайте себе базу для сайта, создайте юзера для работы сайта и поставьте ему доступ по чтению на базу MySQL и полный доступ на свою базу:
Далее необходимо переконнектится к серверу уже из-под вновь созданного юзера и начать создавать нужную структуру таблиц в базе:
Эту структуру (если она будет меняться в вашем проекте) вы можете в любой момент заскриптовать и сохранить в тектовом виде в своем SQL-проекте (см скрины ниже). Кроме того, при работе с MySQL под Windows важно правильно выставить во всех местах кодировку UTF-8 - иначе будет бесконечная чехарда с русскими буквами. В студии DevArt (если вы будете что-то править руками в таблицах и хотете там видеть русский текст, а не абракадабру) - это ставится в свойствах коннекта. А для работы сайта я просто добавляю в конфигурационном файле MySQL.ini команду SET NAMES utf8 (на скринах вы видите куда это вписывается). Кроме того, как вы видите на скринах - я сделал скриптик для рестарта MySQL и указал файл журнала для профилирования SQL-запросов (в журнале видно, как я из админки забанил какого-то юзера).
Для учета пользователей нашего сайта мы создадим следующую структуру таблиц и процедур:
1: -- Скрипт сгенерирован Devart dbForge Studio for MySQL, Версия 4.50.285.1
2: -- Дата: 19/07/2010 23:10:21
3: -- Версия сервера: 5.1.48-community
4: -- Версия клиента: 4.1
5:
6: USE release;
7:
8: CREATE TABLE release.aspnet_users(
9: i INT(12) NOT NULL AUTO_INCREMENT,
10: id VARCHAR(36),
11: Email VARCHAR(50) NOT NULL,
12: Pass VARCHAR(50) NOT NULL,
13: ActivateID VARCHAR(36) NOT NULL,
14: IsActivate TINYINT(1) DEFAULT NULL,
15: CrDate DATETIME NOT NULL,
16: UserName VARCHAR(50) NOT NULL,
17: Name1 VARCHAR(50) DEFAULT NULL,
18: Name2 VARCHAR(50) DEFAULT NULL,
19: IP VARCHAR(16) NOT NULL,
20: IsAdmin TINYINT(1) DEFAULT NULL,
21: IsBan TINYINT(1) DEFAULT NULL,
22: PRIMARY KEY (i, id),
23: UNIQUE INDEX ActivateID (ActivateID),
24: UNIQUE INDEX Email (Email)
25: )
26: ENGINE = INNODB
27: AUTO_INCREMENT = 28
28: AVG_ROW_LENGTH = 16384
29: CHARACTER SET utf8
30: COLLATE utf8_general_ci;
31:
32: CREATE TABLE release.sendmail(
33: i INT(12) NOT NULL AUTO_INCREMENT,
34: CrDate DATETIME NOT NULL,
35: ToAddr VARCHAR(250) NOT NULL,
36: MailSubject VARCHAR(500) NOT NULL,
37: Body VARCHAR(4000) DEFAULT NULL,
38: SendError TINYINT(1) DEFAULT NULL,
39: PRIMARY KEY (i)
40: )
41: ENGINE = INNODB
42: AUTO_INCREMENT = 18
43: CHARACTER SET utf8
44: COLLATE utf8_general_ci;
45:
46: DELIMITER $$
47:
48: CREATE DEFINER = 'release'@'%'
49: PROCEDURE release.AddMail(IN ToAddr VARCHAR(256), IN MailSubject VARCHAR(500), IN Body VARCHAR(4000))
50: BEGIN
51: START TRANSACTION;
52: INSERT
53: release.sendmail (CrDate, ToAddr, MailSubject, Body) VALUES (NOW(), ToAddr, MailSubject, Body);
54: SELECT
55: LAST_INSERT_ID() AS MailId;
56: COMMIT;
57: END
58: $$
59:
60: CREATE DEFINER = 'release'@'%'
61: PROCEDURE release.AddMailError(IN i1 INTEGER, IN SendError1 VARCHAR(1000))
62: BEGIN
63: UPDATE
64: release.sendmail
65: SET
66: SendError = SendError1
67: WHERE
68: i = i1;
69: END
70: $$
71:
72: CREATE DEFINER = 'release'@'%'
73: PROCEDURE release.ClearAllUserInfo(IN id1 VARCHAR(36))
74: BEGIN
75: DECLARE EXIT HANDLER FOR SQLEXCEPTION
76: BEGIN
77: SELECT
78: mysql_error() AS Error_message;
79: END;
80:
81: DELETE
82: FROM
83: release.aspnet_users
84: WHERE
85: id = id1;
86: SELECT
87: NULL AS Error_Number;
88: END
89: $$
90:
91: CREATE DEFINER = 'release'@'%'
92: PROCEDURE release.CreateUser(IN Email VARCHAR(50), IN Pass VARCHAR(50), IN UserName VARCHAR(50), IN Name1 VARCHAR(50), IN Name2 VARCHAR(50), IN IP VARCHAR(16))
93: BEGIN
94: START TRANSACTION;
95: INSERT
96: release.aspnet_users (id, Email, Pass, ActivateID, IsActivate, CrDate, UserName, Name1, Name2, IP, IsAdmin) VALUES (release.StrongGuid(), Email, Pass, release.StrongGuid(), FALSE, NOW(), UserName, Name1, Name2, IP, FALSE);
97: SELECT
98: *
99: FROM
100: release.aspnet_users
101: WHERE
102: i = LAST_INSERT_ID();
103: COMMIT;
104: END
105: $$
106:
107: CREATE DEFINER = 'release'@'%'
108: FUNCTION release.StrongGuid()
109: RETURNS CHAR(36) CHARSET utf8
110: BEGIN
111: DECLARE MD5_hash CHAR(32);
112:
113: SET MD5_hash = MD5(UUID());
114: RETURN CONCAT(
115: SUBSTRING(MD5_hash, 1, 8),
116: '-',
117: SUBSTRING(MD5_hash, 9, 4),
118: '-',
119: SUBSTRING(MD5_hash, 13, 4),
120: '-',
121: SUBSTRING(MD5_hash, 17, 4),
122: '-',
123: SUBSTRING(MD5_hash, 21, 12));
124: END
125: $$
126:
127: DELIMITER ;
Как видите, в этой структуре нет ничего необычного - табличко aspnet_users для учета пользователей, табличко sendmail для учета отправленных писем, табличко audio для работы моего сайтика. Процедурко AddMail для отправки писем и AddMailError для фиксации опибиок при отправке писем, процедурко CreateUser для создания пользователей и ClearAllUserInfo для удаления пользователей. Процедурко CreateAudio для работы моего сайтика и фнукиця StrongGuid для генерации строгого GUID.
Обратите также внимание на имена пользователей - они самодокументируемые в MySQL - после знака @ у них указывается хост - с которого можно входить в MySQL - если % - то с любого.
Теперь посмотрим как правильно сконфигурировать конфиг проекта. Для NET 3.5 полный конфиг проекта будет выглядеть вот так:
1: <?xml version="1.0"?>
2: <configuration>
3: <configSections>
4: <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
5: <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
6: <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
7: <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
8: <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
9: <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
10: <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
11: <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
12: </sectionGroup>
13: </sectionGroup>
14: </sectionGroup>
15: </configSections>
16: <appSettings>
17: <!-- Этот адрес нужен для активации логина -->
18: <add key="HostingURL" value="release.asp-net.ru"/>
19: <add key="NameURL" value="release.ru"/>
20: <add key="AdminURL" value="release-admin.asp-net.ru"/>
21: <!-- Доступ к почтовому серверу -->
22: <add key="SMTP_FromAddr" value="release@asp-net.ru"/>
23: <add key="SMTP_Server" value="XXX.XXX.XXX.XXX"/>
24: <add key="SMTP_Port" value="125"/>
25: <add key="SMTP_Login" value="release@asp-net.ru"/>
26: <add key="SMTP_Pass" value="XXXXXXXXXXXXXXX"/>
27: <!-- Реквизиты главного неудаляемого админа сайта -->
28: <add key="Admin_Login" value="release"/>
29: <add key="Admin_Pass" value="XXXXXXXXXXXXXXX"/>
30: <add key="Admin_Mail" value="info@asp-net.ru"/>
31: </appSettings>
32: <connectionStrings>
33: <add name="MySQLConnectionString" connectionString="Server=release.asp-net.ru;Database=release;User ID=release;Password=XXXXXXXXXX;Connection Timeout=2;Max Pool Size=500;" providerName="MySql.Data.MySqlClient"/>
34: </connectionStrings>
35: <system.web>
36: <compilation debug="true" strict="false" explicit="true">
37: <assemblies>
38: <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
39: <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
40: <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
41: <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
42: <add assembly="MySql.Data, Version=6.2.2.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"/>
43: <add assembly="MySql.Web, Version=6.2.2.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"/>
44: </assemblies>
45: </compilation>
46: <pages>
47: <namespaces>
48: <clear/>
49: <add namespace="System"/>
50: <add namespace="System.Collections"/>
51: <add namespace="System.Collections.Generic"/>
52: <add namespace="System.Collections.Specialized"/>
53: <add namespace="System.Configuration"/>
54: <add namespace="System.Text"/>
55: <add namespace="System.Text.RegularExpressions"/>
56: <add namespace="System.Linq"/>
57: <add namespace="System.Xml.Linq"/>
58: <add namespace="System.Web"/>
59: <add namespace="System.Web.Caching"/>
60: <add namespace="System.Web.SessionState"/>
61: <add namespace="System.Web.Security"/>
62: <add namespace="System.Web.Profile"/>
63: <add namespace="System.Web.UI"/>
64: <add namespace="System.Web.UI.WebControls"/>
65: <add namespace="System.Web.UI.WebControls.WebParts"/>
66: <add namespace="System.Web.UI.HtmlControls"/>
67: </namespaces>
68: <controls>
69: <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
70: <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
71: </controls>
72: </pages>
73: <authentication mode="Forms"/>
74: <httpHandlers>
75: <remove verb="*" path="*.asmx"/>
76: <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
77: <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
78: <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
79: </httpHandlers>
80: <httpModules>
81: <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
82: </httpModules>
83: </system.web>
84: <system.codedom>
85: <compilers>
86: <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
87: <providerOption name="CompilerVersion" value="v3.5"/>
88: <providerOption name="WarnAsError" value="false"/>
89: </compiler>
90: <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
91: <providerOption name="CompilerVersion" value="v3.5"/>
92: <providerOption name="OptionInfer" value="true"/>
93: <providerOption name="WarnAsError" value="false"/>
94: </compiler>
95: </compilers>
96: </system.codedom>
97: <!--
98: The system.webServer section is required for running ASP.NET AJAX under Internet
99: Information Services 7.0. It is not necessary for previous version of IIS.
100: -->
101: <system.webServer>
102: <validation validateIntegratedModeConfiguration="false"/>
103: <modules>
104: <remove name="ScriptModule"/>
105: <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
106: </modules>
107: <handlers>
108: <remove name="WebServiceHandlerFactory-Integrated"/>
109: <remove name="ScriptHandlerFactory"/>
110: <remove name="ScriptHandlerFactoryAppServices"/>
111: <remove name="ScriptResource"/>
112: <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
113: <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
114: <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
115: </handlers>
116: </system.webServer>
117: <runtime>
118: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
119: <dependentAssembly>
120: <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
121: <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
122: </dependentAssembly>
123: <dependentAssembly>
124: <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
125: <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
126: </dependentAssembly>
127: </assemblyBinding>
128: </runtime>
129: </configuration>
Это совершенно стандартный конфиг ASP.NEt 3.5 за исключением параметров, которые я внес в секцию <appSettings> и параметров коннекта серверу MySQL - которые опять же совершенно понятны, возможно за исключением параметра Timeout=2, который означает время жизни SQL-запроса в сервере MySQL. Это достаточно важный параметр, если его не закрутить в минимум, то пул коннектов коннектов в MySQL (максимальное количество которых установлено в конфиге) мгновенно исчерпается.
Теперь перейдем к коду сайта. Он будет состоять из пяти компонентов, доступных пользователю и трех компонентов админки. Публичная часть сайта будет состоять из контрола для регистрации left.ascx, странички для регистрации Register.aspx, странички ожидания подтверждения регистрации Pending.aspx, странички активации логина ActivateLogin.aspx и странички напоминания пароля RestorePass.aspx.
Итак, в некотором месте моего проекта (в контроле, размещенном на master.page) лежил код разметки для логина в сайт (в данном случае это контрол left.ascx):
1: <asp:Panel ID="Panel1" runat="server">
2: <table border="0" cellpadding="0" cellspacing="0" style="width: 250px; vertical-align: top;
3: text-align: left">
4: <tr>
5: <td>
6: <asp:TextBox ID="txLogin" runat="server" Width="150px"></asp:TextBox>
7: <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="txLogin"
8: ErrorMessage="*" ValidationGroup="Login"></asp:RequiredFieldValidator>
9: </td>
10: <td rowspan="2">
11: <asp:ImageButton ID="btLogin" runat="server" ImageUrl="~/Image/Login.png" ValidationGroup="Login" />
12: <asp:Label ID="Lerr1" runat="server" ForeColor="Red"></asp:Label>
13: </td>
14: </tr>
15: <tr>
16: <td>
17: <asp:TextBox ID="txPass" runat="server" Width="150px"></asp:TextBox>
18: <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ControlToValidate="txPass"
19: ErrorMessage="*" ValidationGroup="Login"></asp:RequiredFieldValidator>
20: </td>
21: <td>
22: </td>
23: </tr>
24: <tr style="height: 10px">
25: <td>
26: </td>
27: <td>
28: </td>
29: </tr>
30: <tr>
31: <td>
32: <asp:HyperLink ID="ForgotPass" runat="server" ForeColor="White" Font-Names="Segoe UI"
33: Font-Size="12px" NavigateUrl="~/RestorePass.aspx">Forgot our password</asp:HyperLink>
34: </td>
35: <td>
36: </td>
37: </tr>
38: <tr>
39: <td>
40: <asp:HyperLink ID="CreateAccount" runat="server" ForeColor="White" Font-Names="Segoe UI"
41: Font-Size="12px" NavigateUrl="~/Register.aspx">Create new account</asp:HyperLink>
42: </td>
43: <td>
44: </td>
45: </tr>
46: </table>
47: </asp:Panel>
48: <asp:Panel ID="Panel2" runat="server">
49: <asp:HyperLink ID="CabLink1" runat="server" ForeColor="White" Font-Names="Segoe UI"
50: Font-Size="12px" ></asp:HyperLink>
51: <br />
52: <asp:LinkButton ID="LogoutButton1" runat="server" ForeColor="White" Font-Names="Segoe UI"
53: Font-Size="12px">Logout</asp:LinkButton>
54:
55: <asp:LinkButton ID="AdminButton1" runat="server" ForeColor="White" Font-Names="Segoe UI"
56: Font-Size="12px">Admin</asp:LinkButton>
57:
58: <div style="height:63px"/>
59: </asp:Panel>
Как видите, контрол логина состоит из двух панелей, которые переключаются в зависимости от того, залогинен юзер или нет. А код контрола залогинивания выглядит вот так:
1: Partial Class Left
2: Inherits System.Web.UI.UserControl
3:
4: Protected Sub Left_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
5: If Not IsPostBack Then
6: If HttpContext.Current.User.Identity.IsAuthenticated Then
7: Panel1.Visible = False
8: Panel2.Visible = True
9: CabLink1.Text = CType(Me.Page, BasePage).User_UserName
10: CabLink1.NavigateUrl = "Cab.aspx?user=" & CType(Me.Page, BasePage).User_id
11: If CType(Me.Page, BasePage).User_IsAdmin Then
12: AdminButton1.Visible = True
13: AdminButton1.PostBackUrl = "http://" & System.Configuration.ConfigurationManager.AppSettings("AdminURL").ToString
14: Else
15: AdminButton1.Visible = False
16: End If
17: Else
18: Panel1.Visible = True
19: Panel2.Visible = False
20: End If
21: End If
22: End Sub
23:
24:
25: Protected Sub btLogin_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles btLogin.Click
26: Try
27: Dim GetOneUser As New ExecMySQL_RDR("UserName", txLogin.Text)
28: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = GetOneUser.ExecMySQL("select * from releasebeat.aspnet_users where UserName=@UserName", Data.CommandType.Text)
29: If DR1.Read Then
30: If DR1("Pass") = txPass.Text Then
31: FormsAuthentication.SetAuthCookie(txLogin.Text, True)
32: Panel1.Visible = False
33: Panel2.Visible = True
34: CabLink1.Text = DR1("UserName")
35: CabLink1.NavigateUrl = "Cab.aspx?user=" & DR1("id")
36: If DR1("IsAdmin") Then
37: AdminButton1.Visible = True
38: AdminButton1.PostBackUrl = "http://" & System.Configuration.ConfigurationManager.AppSettings("AdminURL").ToString
39: Else
40: AdminButton1.Visible = False
41: End If
42: If Not DR1("IsActivate") Then
43: Panel1.Visible = False
44: Panel2.Visible = True
45: Response.Redirect("Pending.aspx")
46: End If
47: End If
48: End If
49: Lerr1.Text = ""
50: Catch ex As Exception
51: Lerr1.Text = ex.Message
52: End Try
53: End Sub
54:
55: Protected Sub LinkButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles LogoutButton1.Click
56: FormsAuthentication.SignOut()
57: Panel1.Visible = True
58: Panel2.Visible = False
59: End Sub
60:
61: End Class
Как видите, это совершенно тривиальный код обращения в базу и проверки - есть ли там нужный нам юзер. Обратите внимание, что обращение в базу производится с помощью моей ADO.NET обвязка для работы с MySQL в ASP.NET-сайтах под Windows.
Как я уже говорил, я провожу границу стандартного и нестандартного кода каждого сайта не там, где ее проводит микрософт. Для меня это обязательно капча при регистрации и письмо об активации. Для микрософта это что-то совершенно иное - тмпо их убогих активационных контролов. Поэтому мой следующий фрагмент стандартного ASP-NET сайта - это страничка регистрации Register.aspx, высылающая активационные письма. Ссылка на эту страничку стоит в контроле залогинивания, а в страничке регистрации есть фрагмент с полями, которые должен заполнить юзер, главное из которых его Email-адрес:
1: <table cellpadding="0" cellspacing="0" border="0" style="display: inline">
2: <tr>
3: <td>
4: <asp:Label ID="lblNewError" runat="server" Visible="false" CssClass="error" Text="You have entered incorrect login or password."></asp:Label>
5: <br />
6: <div class="form">
7: Please fill in the form to create a new account.<br />
8: <span>First Name:</span>
9: <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
10: ErrorMessage="*" ControlToValidate="tbxFirstName" ValidationGroup="Create1"></asp:RequiredFieldValidator>
11: <asp:TextBox ID="tbxFirstName" runat="server"></asp:TextBox><br />
12: <br />
13: <span>Last Name:</span>
14: <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server"
15: ErrorMessage="*" ControlToValidate="tbxLastName" ValidationGroup="Create1"></asp:RequiredFieldValidator>
16: <asp:TextBox ID="tbxLastName" runat="server"></asp:TextBox><br />
17: <br />
18: <span>Login:</span>
19: <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server"
20: ErrorMessage="*" ControlToValidate="tbxNewLogin" ValidationGroup="Create1"></asp:RequiredFieldValidator>
21: <asp:TextBox ID="tbxNewLogin" runat="server"></asp:TextBox><br />
22: <br />
23: <span>Password:</span>
24: <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server"
25: ErrorMessage="*" ControlToValidate="tbxNewPassword" ValidationGroup="Create1"></asp:RequiredFieldValidator>
26: <asp:TextBox ID="tbxNewPassword" runat="server" TextMode="Password"></asp:TextBox><br />
27: <br />
28: <span>Email:</span>
29: <asp:RequiredFieldValidator ID="RequiredFieldValidator5" runat="server"
30: ErrorMessage="*" ControlToValidate="tbxNewEmail" ValidationGroup="Create1"></asp:RequiredFieldValidator>
31: <asp:TextBox ID="tbxNewEmail" runat="server"></asp:TextBox><br />
32: <br />
33: <span>I agree with the terms<asp:CheckBox ID="cbxAgree" runat="server"></asp:CheckBox></span><br />
34: <br />
35: <div class="agreement">
36: According to author's right all materials which presented on <b>releasebeat.ru</b>
37: website are presented for advertising and acquaintance purposes and shouldn't be
38: used for further coping public presentation. Otherwise you should take personal
39: responsibility for illegal coping of materials. After downloading mp-3 files you
40: must buy the licensed product of the author you prefer.<br />
41: <br />
42: </div>
43: * all fields are obligatory<br />
44: <br />
45: </div>
46: <asp:Button ID="btnCreate" runat="server" CssClass="button" Text="Create" ValidationGroup="Create1" />
47: </td>
48: </tr>
49: </table>
Как я уже говорил, моя капча в ее нынешнем виде не является OpenSource-кодом - это элемент защиты сайта от взлома и такие вещи, которые могут нанести ущерб моим партнерам и заказчикам - я не публикую. Поэтому этот OpenSource-код побликуется без капчи - хотя в нормальном сайте регисрации без кампчи конечно быть не может. (моя капча входит в состав моего решения AspNet_UserManager - компонент сайта для управления пользователями).
Код странички регистрации выглядит вот так:
1: Partial Class Register
2: Inherits BasePage
3:
4: Protected Sub CreateCommand(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCreate.Click
5: Dim UserID As String, ActivateID As String
6: Try
7: CreateUser.SelectParameters("Email").DefaultValue = tbxNewEmail.Text
8: CreateUser.SelectParameters("Pass").DefaultValue = tbxNewPassword.Text
9: CreateUser.SelectParameters("UserName").DefaultValue = tbxNewLogin.Text
10: CreateUser.SelectParameters("Name1").DefaultValue = tbxFirstName.Text
11: CreateUser.SelectParameters("Name2").DefaultValue = tbxLastName.Text
12: CreateUser.SelectParameters("IP").DefaultValue = HttpContext.Current.Request.UserHostAddress
13: Dim DV1 As Data.DataView = CreateUser.Select(New DataSourceSelectArguments)
14: If DV1 IsNot Nothing Then
15: If DV1.Count > 0 Then
16: UserID = DV1(0)("ID")
17: ActivateID = DV1(0)("ActivateID")
18: Else
19: lblNewError.Visible = True
20: lblNewError.Text = "CreateUser Error 1"
21: Exit Sub
22: End If
23: Else
24: lblNewError.Visible = True
25: lblNewError.Text = "CreateUser Error 2"
26: Exit Sub
27: End If
28: Catch ex1 As MySql.Data.MySqlClient.MySqlException
29: If ex1.Message.StartsWith("Duplicate entry") Then
30: lblNewError.Visible = True
31: lblNewError.Text = "Такой пользователь уже зарегистрирован"
32: Exit Sub
33: Else
34: lblNewError.Visible = True
35: lblNewError.Text = "CreateUser Error" & vbCrLf & ex1.Message
36: Exit Sub
37: End If
38: Catch ex As Exception
39: lblNewError.Visible = True
40: lblNewError.Text = "CreateUser Error" & vbCrLf & ex.Message
41: Exit Sub
42: End Try
43: '
44: Try
45: FormsAuthentication.SetAuthCookie(tbxNewEmail.Text, True)
46: '
47: 'признак аутентификации для клиентского скрипта
48: Dim AU_Cook As New HttpCookie("AU")
49: AU_Cook.Item("U") = 1
50: Catch ex As Exception
51: lblNewError.Visible = True
52: lblNewError.Text = "Cookie Error" & vbCrLf & ex.Message
53: Exit Sub
54: End Try
55: '
56: Try
57: 'и отправляем мыло для активации логина
58: 'тут тоже возможен баг - SendMail_Error: Mailbox unavailable. The server response was: non-local recipient verification failed
59: Mail1.SendMail(tbxNewEmail.Text, "Активация логина " & System.Configuration.ConfigurationManager.AppSettings("NameURL"), "<html><body>Здравствуйте, " & tbxNewLogin.Text & " <br><br>Добро пожаловать на сайт " & System.Configuration.ConfigurationManager.AppSettings("NameURL") & " <br><br>Параметры вашей учётной записи таковы: " & _
60: "<br><br><b>Логин:</b>" & tbxNewLogin.Text & _
61: "<br><br><b>Пароль:</b> " & tbxNewPassword.Text & _
62: "<br><br>Ваша учётная запись ещё не активна. Вы не сможете ей пользоваться, пока не перейдёте по следующей ссылке:" & _
63: "<br><a href=""http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "/ActivateLogin.aspx?i=" & UserID & "&j=" & ActivateID & """> http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "/ActivateLogin.aspx?i=" & UserID & "&j=" & ActivateID & "</a><br>" & _
64: "<br><br>Если указанная выше ссылка не открывается, скопируйте ее в буфер обмена, вставьте в адресную строку браузера и нажмите ввод." & _
65: "<br><br>Желаем Вам удобного, приятного общения и хорошего отдыха!" & _
66: "<br><br>Если данное письмо послано Вам ошибочно, то проигнорируйте его и все данные будут автоматически удалены." & _
67: "<br><br>___________________<br>C уважением,<br> Администрация <a href='http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "'>" & System.Configuration.ConfigurationManager.AppSettings("NameURL") & "</a></body></html>")
68: System.Web.Security.FormsAuthentication.RedirectFromLoginPage(tbxNewEmail.Text, True)
69: Response.Redirect("Pending.aspx")
70: Catch ex As Exception
71: Response.Redirect("Pending.aspx?txt=" & "Ошибка, пользователь создан, но из-за почтовых проблем сообщение для активации не отправлено. Попробуйте повторно выслать письмо активации из кабинета пользователя." & ex.Message)
72: End Try
73: End Sub
74: End Class
Эта страничка рассылает вот такие письма об активации.
Теперь нам потребуется еще страничка ожидания Pending.aspx, куда юзер попадает после регистрации. Она тоже состоит из двух панелей (в зависимости есть кука залогиненного юзера или нет) и кнопки повторения посылки активационного письма:
1: <asp:Content ID="Content3" ContentPlaceHolderID="RightPlaceHolder2" runat="Server">
2: <table cellpadding="0" cellspacing="0" border="0" style="display: inline">
3: <tr>
4: <td>
5: <asp:Panel ID="Panel1" runat="server">
6: <asp:Label ID="Label1" runat="server">Вам выслано письмо об активации.<br>
7: Пока вы не активируете свой логин - работа с сайтом невозможна.<br />
8: Вы можете выслать повторно письмо об активации, однако несколько одинаковых писем<br />
9: могут привести к полной блокировке отправителя на вашем почтовом сервере.<br />
10: Если письма об активации не доходят совершенно, попробуйте зарегистрироваться еще раз<br />
11: с почтовым ящиков на другом почтовом сервере.</asp:Label>
12: <br />
13: <br />
14: <asp:LinkButton ID="LinkButton1" runat="server">Выслать письмо для активации повторно</asp:LinkButton>
15: </asp:Panel>
16: <asp:Panel ID="Panel2" runat="server">
17: <asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="Image/Logo.png" />
18: </asp:Panel>
19: <asp:Label ID="Lerr1" runat="server" ForeColor="Red"></asp:Label>
20:
21: </td>
22: </tr>
23: </table>
24: <asp:SqlDataSource ID="GetOneUser" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
25: ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>"
26: SelectCommand="select * from releasebeat.aspnet_users where email=@Email;">
27: <SelectParameters>
28: <asp:Parameter Name="Email" Type="String" />
29: </SelectParameters>
30: </asp:SqlDataSource>
31: </asp:Content>
Код странички Pending.aspx такой:
1: Partial Class Pending
2: Inherits BasePage
3:
4: Protected Sub Pending_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
5: If Not IsPostBack Then
6: If HttpContext.Current.User.Identity.IsAuthenticated Then
7: Panel1.Visible = True
8: Panel2.Visible = False
9: Else
10: Panel1.Visible = False
11: Panel2.Visible = True
12: End If
13: End If
14: End Sub
15:
16: Protected Sub LinkButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles LinkButton1.Click
17: Try
18: GetOneUser.SelectParameters("Email").DefaultValue = "1@1.ru" 'HttpContext.Current.User.Identity.Name"
19: Dim Dv1 As Data.DataView = GetOneUser.Select(New DataSourceSelectArguments)
20: If Dv1 IsNot Nothing Then
21: If Dv1.Count > 0 Then
22: Try
23: Mail1.SendMail(Dv1(0)("Email"), "Активация логина " & System.Configuration.ConfigurationManager.AppSettings("NameURL"), "<html><body>Здравствуйте, " & Dv1(0)("UserName") & " <br><br>Добро пожаловать на сайт " & System.Configuration.ConfigurationManager.AppSettings("NameURL") & " <br><br>Параметры вашей учётной записи таковы: " & _
24: "<br><br><b>Логин:</b>" & Dv1(0)("UserName") & _
25: "<br><br><b>Пароль:</b> " & Dv1(0)("Pass") & _
26: "<br><br>Ваша учётная запись ещё не активна. Вы не сможете ей пользоваться, пока не перейдёте по следующей ссылке:" & _
27: "<br><a href=""http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "/ActivateLogin.aspx?i=" & Dv1(0)("id") & "&j=" & Dv1(0)("ActivateID") & """> http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "/ActivateLogin.aspx?i=" & Dv1(0)("id") & "&j=" & Dv1(0)("ActivateID") & "</a><br>" & _
28: "<br><br>Если указанная выше ссылка не открывается, скопируйте ее в буфер обмена, вставьте в адресную строку браузера и нажмите ввод." & _
29: "<br><br>Желаем Вам удобного, приятного общения и хорошего отдыха!" & _
30: "<br><br>Если данное письмо послано Вам ошибочно, то проигнорируйте его и все данные будут автоматически удалены." & _
31: "<br><br>___________________<br>C уважением,<br> Администрация <a href='http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "'>" & System.Configuration.ConfigurationManager.AppSettings("NameURL") & "</a></body></html>")
32: Catch ex As Exception
33: Lerr1.Text = "SendMail Error. " & vbCrLf & ex.Message
34: End Try
35: Else
36: Lerr1.Text = "Error 1"
37: End If
38: Else
39: Lerr1.Text = "Error 2"
40: End If
41: Catch ex As Exception
42: Lerr1.Text = "Error. " & vbCrLf & ex.Message
43: End Try
44: End Sub
45:
46:
47: End Class
Эти странички рассылают письма с помощью вот такой небольшой обвязки вокруг класса MailClient, который ведет журнал рассылки активационных писем в базе MySQL:
1: Imports Microsoft.VisualBasic
2: Imports System, System.Web
3:
4: Public Class Mail1
5: Public Shared Sub SendMail(ByVal ToAddr As String, ByVal Subject As String, ByVal Body As String)
6: Dim SendedMailID As Integer
7: Dim AddMail As New ExecMySQL_RDR("ToAddr", ToAddr, "MailSubject", Subject, "Body", Body)
8: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = AddMail.ExecMySQL("AddMail", Data.CommandType.StoredProcedure)
9: If DR1.Read Then
10: SendedMailID = DR1("MailId")
11: End If
12: Try
13: Dim Email As New System.Net.Mail.MailMessage(System.Configuration.ConfigurationManager.AppSettings("SMTP_FromAddr"), ToAddr, Subject, Body)
14: Email.IsBodyHtml = True 'для форматированной почты
15: 'Email.Attachments.Add(New system.Net.Mail.Attachment(...))
16: Dim MailClient As New System.Net.Mail.SmtpClient()
17: Dim basicAuthenticationInfo As New System.Net.NetworkCredential(System.Configuration.ConfigurationManager.AppSettings("SMTP_Login"), System.Configuration.ConfigurationManager.AppSettings("SMTP_Pass"))
18: MailClient.Host = System.Configuration.ConfigurationManager.AppSettings("SMTP_Server")
19: MailClient.Port = System.Configuration.ConfigurationManager.AppSettings("SMTP_Port")
20: MailClient.UseDefaultCredentials = False
21: MailClient.Credentials = basicAuthenticationInfo
22: MailClient.Send(Email)
23: Catch ex As Exception
24: My.Log.WriteEntry(System.Configuration.ConfigurationManager.AppSettings("SMTP_FromAddr") & "->" & ToAddr & ":" & Subject & ":" & Body & vbCrLf & "SendMail_Error: " & ex.Message)
25: Dim AddMailError As New ExecMySQL_RDR("i1", SendedMailID, "SendError1", ex.Message)
26: AddMailError.ExecMySQL("AddMailError", Data.CommandType.StoredProcedure)
27: End Try
28: End Sub
29:
30: End Class
Обрабатывает активационные письма страничка ActivateLogin.aspx. Для разнообразия я сделал в ней обращения в MySQL Через SqlDataSource - хотя мой опыт показывает что работает он нестабильно - и даже когда у него все параметры сконфигурированы - он часто падает, ибо обращается к провайдеру MS SQL.
Поэтому, посмотрев на логику этой странички, вам лучше ее заменить на обращения к MySQL через мой более надежно работающий враппер ExecMySQL_RDR.
1: <asp:Content ID="Content3" ContentPlaceHolderID="RightPlaceHolder2" runat="Server">
2: <table cellpadding="0" cellspacing="0" border="0" style="display: inline">
3: <tr>
4: <td>
5: <asp:Literal ID="Literal1" runat="server"></asp:Literal>
6: </td>
7: </tr>
8: </table>
9: <asp:SqlDataSource ID="GetOneUser" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
10: ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>"
11: SelectCommand="select * from releasebeat.aspnet_users where id=@id;">
12: <SelectParameters>
13: <asp:Parameter Name="id" Type="String" />
14: </SelectParameters>
15: </asp:SqlDataSource>
16:
17: <asp:SqlDataSource ID="ActivateUser" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
18: ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>"
19: SelectCommand="Update releasebeat.aspnet_users Set IsActivate=True where id=@id;">
20: <SelectParameters>
21: <asp:Parameter Name="id" Type="String" />
22: </SelectParameters>
23: </asp:SqlDataSource>
24: </asp:Content>
Собственно код странички активации выглядит вот так:
1: Partial Class ActivateLogin
2: Inherits BasePage
3:
4: Protected Sub ActivateLogin_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
5: If Not IsPostBack Then
6: If Context.Request.QueryString("i") <> "" And Context.Request.QueryString("j") <> "" Then
7: Dim UserID As Guid
8: Dim ActivateID As Guid
9: Try
10: UserID = New Guid(Context.Request.QueryString("i"))
11: ActivateID = New Guid(Context.Request.QueryString("j"))
12: Catch ex As Exception
13: Throw New Exception("Указаны неверные параметры")
14: End Try
15: GetOneUser.SelectParameters("id").DefaultValue = UserID.ToString
16: Dim DV1 As Data.DataView = GetOneUser.Select(New DataSourceSelectArguments)
17: If DV1 IsNot Nothing Then
18: Dim SavedGuid As String = DV1(0)("ActivateID")
19: If SavedGuid = Context.Request.QueryString("j") Then
20: If Not DV1(0)("IsActivate") Then
21: Try
22: ActivateUser.SelectParameters("id").DefaultValue = UserID.ToString
23: ActivateUser.Select(New DataSourceSelectArguments)
24: Catch ex As Exception
25: Throw New Exception("Ошибка." & ex.Message)
26: End Try
27: Literal1.Text = "Поздравляем!<br> Вы зарегистрированы в проекте " & System.Configuration.ConfigurationManager.AppSettings("RealURL") & "<br>Желаем Вам приятного отдыха!<br><br>"
28: Response.Redirect("Default.aspx")
29: Else
30: Literal1.Text = "Вы уже активированны в проекте " & System.Configuration.ConfigurationManager.AppSettings("RealURL") & "<br>Желаем Вам удобного, приятного отдыха!<br><br>"
31: End If
32: Else
33: Literal1.Text = "Неверный параметр активации."
34: End If
35: Else
36: Literal1.Text = "Пользователя не существует."
37: End If
38: Else
39: Throw New Exception("Dos атака")
40: End If
41: End If
42:
43: End Sub
44:
45:
46: End Class
Все что нам нужно на внешней контактной поверхности сайта - это еще страничка напоминания пароля RestorePass.aspx (ссылка на которую тоже должны быть на залогинивающем контроле). Эта страничка может выглядеть так:
1: <asp:Content ID="Content3" ContentPlaceHolderID="RightPlaceHolder2" runat="Server">
2:
3: <table cellpadding="0" cellspacing="0" border="0" style="display: inline">
4: <tr>
5: <td>
6: <asp:Label ID="lblMessage" runat="server" Visible="false" Text=""></asp:Label>
7: <asp:Panel ID="pnlForgotPass" runat="server">
8: <asp:Label ID="lblError" runat="server" Visible="false" CssClass="error" Text="You have entered incorrect login or password."></asp:Label>
9: <br />
10: Type your login or email if you want to restore your password.
11: <div class="form">
12: <br />
13: <br />
14: <span>Login:</span>
15: <asp:TextBox ID="tbxForgotLogin" runat="server"></asp:TextBox><br />
16: <br />
17: OR<br />
18: <br />
19: <span>Email:</span>
20: <asp:TextBox ID="tbxForgotEmail" runat="server"></asp:TextBox><br />
21: <br />
22: </div>
23: <asp:Button ID="btnRemember" runat="server" CssClass="button" Text="REMEMBER" OnClick="RememberCommand" />
24: <br /><asp:Label ID="Lerr1" runat="server" ForeColor="Red"></asp:Label>
25: </asp:Panel>
26: </td>
27: </tr>
28: </table>
29:
30: <asp:SqlDataSource ID="GetUserForName" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
31: ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>"
32: SelectCommand="select * from releasebeat.aspnet_users where UserName=@UserName;">
33: <SelectParameters>
34: <asp:Parameter Name="UserName" Type="String" />
35: </SelectParameters>
36: </asp:SqlDataSource>
37:
38: <asp:SqlDataSource ID="GetUserForMail" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
39: ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>"
40: SelectCommand="select * from releasebeat.aspnet_users where Email=@Email;">
41: <SelectParameters>
42: <asp:Parameter Name="Email" Type="String" />
43: </SelectParameters>
44: </asp:SqlDataSource>
45:
46: </asp:Content>
1: Partial Class RestorePass
2: Inherits BasePage
3:
4: Protected Sub RememberCommand(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnRemember.Click
5: Try
6: If tbxForgotEmail.Text <> "" Then
7: GetUserForMail.SelectParameters("Email").DefaultValue = tbxForgotEmail.Text
8: Dim DV1 As Data.DataView = GetUserForMail.Select(New DataSourceSelectArguments)
9: If DV1 IsNot Nothing Then
10: If DV1.Count > 0 Then
11: If DV1(0)("IsActive") Then
12: Mail1.SendMail(DV1(0)("Email"), "Активация логина " & System.Configuration.ConfigurationManager.AppSettings("NameURL"), "<html><body>Здравствуйте, " & DV1(0)("UserName") & " <br><br>Добро пожаловать на сайт " & System.Configuration.ConfigurationManager.AppSettings("NameURL") & " <br><br>Параметры вашей учётной записи таковы: " & _
13: "<br><br><b>Логин:</b>" & DV1(0)("UserName") & _
14: "<br><br><b>Пароль:</b> " & DV1(0)("Pass") & _
15: "<br><br>Если данное письмо послано Вам ошибочно, то проигнорируйте его." & _
16: "<br><br>___________________<br>C уважением,<br> Администрация <a href='http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "'>" & System.Configuration.ConfigurationManager.AppSettings("NameURL") & "</a></body></html>")
17: End If
18: End If
19: End If
20: ElseIf tbxForgotLogin.Text <> "" Then
21: GetUserForName.SelectParameters("UserName").DefaultValue = tbxForgotLogin.Text
22: Dim DV2 As Data.DataView = GetUserForName.Select(New DataSourceSelectArguments)
23: If DV2 IsNot Nothing Then
24: If DV2.Count > 0 Then
25: If DV2(0)("IsActive") Then
26: Mail1.SendMail(DV2(0)("Email"), "Активация логина " & System.Configuration.ConfigurationManager.AppSettings("NameURL"), "<html><body>Здравствуйте, " & DV2(0)("UserName") & " <br><br>Добро пожаловать на сайт " & System.Configuration.ConfigurationManager.AppSettings("NameURL") & " <br><br>Параметры вашей учётной записи таковы: " & _
27: "<br><br><b>Логин:</b>" & DV2(0)("UserName") & _
28: "<br><br><b>Пароль:</b> " & DV2(0)("Pass") & _
29: "<br><br>Если данное письмо послано Вам ошибочно, то проигнорируйте его." & _
30: "<br><br>___________________<br>C уважением,<br> Администрация <a href='http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "'>" & System.Configuration.ConfigurationManager.AppSettings("NameURL") & "</a></body></html>")
31: End If
32: End If
33: End If
34: End If
35: Response.Redirect("Default.aspx")
36: Catch ex As Exception
37: Lerr1.Text = ex.Message
38: End Try
39:
40: End Sub
Все что нам нужно еще в части управления пользователями - это смена пароля. Это можно сделать в кабинете пользователя наряду с другими специфическими параметрами профиля пользователя. С точки зрения управления пользователями - это простой Update в базу.
Теперь рассмотрим ту часть управления пользователями, которую видит только админ сайта. Как вы понимаете, админка - это совсем другой сайт. Например для сайта votpusk.ru админка выглядит вот так - Опыт видео-конвертации. Хотя во множестве проектов у меня нету выделенной админки - формы управления юзерами находятся в основном проекте. Если же есть выделенная админка в другом домене, то ее конфиг точно такой же, как конфиг основного сайта.
Для нашего OpenSource-проекта админка юзеров сайта будет состоять из трех небольших страничек admin_user_activate.aspx, admin_user_list.aspx, admin_clear_user.aspx.
Страничка admin_user_activate.aspx предназначена для активации пользователей вручную - в тех случаях когда они просят об этом по телефону из-за того, что активационное мыло до них не проходит спам-фильтры. |
1: <%@ Page Language="VB" MasterPageFile="~/M1.master" AutoEventWireup="false" CodeFile="admin_user_activate.aspx.vb" Inherits="admin_user_activate" %>
2:
3: <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
4: <h4>Активация пользователя</h4>
5:
6: <table>
7:
8: <tr><td colspan="2"><asp:Label ID="Label2" runat="server" Text="UserName"></asp:Label></td></tr>
9: <tr><td><asp:TextBox ID="TextBox1" runat="server" Width="300px"></asp:TextBox>
10: </td><td><asp:Button ID="Button1" runat="server" Text="Проверить" Width="100px" />
11:
12: </td></tr><tr><td><asp:Label ID="Label1" runat="server"></asp:Label>
13: </td><td><asp:Button ID="Button2" runat="server" Enabled="False" Text="Активировать" Width="100px" />
14: </td></tr></table>
15: <asp:Label ID="Lerr1" runat="server" ForeColor="Red"></asp:Label>
16:
17: <asp:SqlDataSource ID="GetOneUserByName" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
18: ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>"
19: SelectCommand="select * from releasebeat.aspnet_users where UserName=@UserName;">
20: <SelectParameters>
21: <asp:Parameter Name="UserName" Type="String" />
22: </SelectParameters>
23: </asp:SqlDataSource>
24:
25: <asp:SqlDataSource ID="GetOneUserByID" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
26: ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>"
27: SelectCommand="select * from releasebeat.aspnet_users where id=@id;">
28: <SelectParameters>
29: <asp:Parameter Name="id" Type="String" />
30: </SelectParameters>
31: </asp:SqlDataSource>
32:
33:
34: <asp:SqlDataSource ID="ActivateUser" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
35: ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>"
36: SelectCommand="Update releasebeat.aspnet_users Set IsActivate=True where id=@id;">
37: <SelectParameters>
38: <asp:Parameter Name="id" Type="String" />
39: </SelectParameters>
40: </asp:SqlDataSource>
41:
42: </asp:Content>
В сущности это просто запись однобитного флажка в базу MySQL:
1:
2: Partial Class admin_user_list
3: Inherits BasePage
4:
5: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
6: If Not IsPostBack Then
7: If Session("admin_user_list_filter") Is Nothing Then Session("admin_user_list_filter") = ""
8: FilterBox.Text = Session("admin_user_list_filter")
9: CurrentFields.Value = "UserName"
10: CurrentDirection.Value = WebControls.SortDirection.Ascending
11: Refresh()
12: End If
13: End Sub
14:
15: Sub Refresh()
16: Try
17: Dim Filter As String = Session("admin_user_list_filter")
18:
19: Dim DT As New Data.DataTable("Filtered_users")
20: DT.Columns.Add("i", GetType(System.Int32))
21: DT.Columns.Add("id", GetType(System.String))
22: DT.Columns.Add("Email", GetType(System.String))
23: DT.Columns.Add("Pass", GetType(System.String))
24: DT.Columns.Add("IsActivate", GetType(System.Boolean))
25: DT.Columns.Add("CrDate", GetType(System.DateTime))
26: DT.Columns.Add("UserName", GetType(System.String))
27: DT.Columns.Add("Name1", GetType(System.String))
28: DT.Columns.Add("Name2", GetType(System.String))
29: DT.Columns.Add("IP", GetType(System.String))
30: DT.Columns.Add("IsAdmin", GetType(System.Boolean))
31: DT.Columns.Add("IsBan", GetType(System.Boolean))
32:
33: Dim GetAllUsers2 As New ExecMySQL_RDR()
34: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = GetAllUsers2.ExecMySQL("select * from releasebeat.aspnet_users order by i", Data.CommandType.Text)
35: While DR1.Read
36: If Filter = "" Or DR1("UserName").Contains(Filter) Then
37: Dim OneRow As System.Data.DataRow = DT.NewRow
38: OneRow("i") = DR1("i")
39: OneRow("id") = DR1("id")
40: OneRow("Email") = DR1("Email")
41: OneRow("Pass") = DR1("Pass")
42: OneRow("IsActivate") = DR1("IsActivate")
43: OneRow("CrDate") = DR1("CrDate")
44: OneRow("UserName") = DR1("UserName")
45: OneRow("Name1") = DR1("Name1")
46: OneRow("Name2") = DR1("Name2")
47: OneRow("IP") = DR1("IP")
48: OneRow("IsAdmin") = DR1("IsAdmin")
49: OneRow("IsBan") = DR1("IsBan")
50: DT.Rows.Add(OneRow)
51: End If
52: End While
53:
54: GridView1.AutoGenerateColumns = False
55: 'Dim UserNameColumn As New ui.WebControls.HyperLinkField 'колонки можно выставить и в коде
56: Dim SortExpression As String
57: If CurrentDirection.Value = WebControls.SortDirection.Ascending Then
58: SortExpression = CurrentFields.Value & " asc"
59: Else
60: SortExpression = CurrentFields.Value & " desc"
61: End If
62: Dim DV1 As Data.DataView
63: If Filter = "" Then
64: DV1 = New Data.DataView(DT, "UserName like '%*%'", SortExpression, Data.DataViewRowState.CurrentRows)
65: Else
66: DV1 = New Data.DataView(DT, "UserName like '%" & Filter & "%'", SortExpression, Data.DataViewRowState.CurrentRows)
67: End If
68: GridView1.DataSource = DV1
69: GridView1.DataMember = "Filtered_users"
70: Dim KeyArr() As String = {"id"}
71: GridView1.DataKeyNames = KeyArr 'баг бейсика - запрет онлайнового обьявления массива
72: GridView1.DataBind()
73: Catch ex As Exception
74: Lerr1.Text = ex.Message
75: End Try
76:
77: End Sub
78:
79:
80: Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
81: GridView1.PageIndex = e.NewPageIndex
82: Refresh()
83: End Sub
84:
85: Protected Sub GridView1_Sorting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewSortEventArgs) Handles GridView1.Sorting
86: CurrentFields.Value = e.SortExpression
87: If CurrentDirection.Value = WebControls.SortDirection.Ascending Then
88: CurrentDirection.Value = WebControls.SortDirection.Descending
89: Else
90: CurrentDirection.Value = WebControls.SortDirection.Ascending
91: End If
92: Refresh()
93: End Sub
94:
95: Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
96: If e.Row.DataItem IsNot Nothing Then
97: Dim UnBan_Button1 As LinkButton = CType(e.Row.FindControl("UnBan_Button1"), LinkButton)
98: Dim Ban_Button1 As LinkButton = CType(e.Row.FindControl("Ban_Button1"), LinkButton)
99: If IsDBNull(e.Row.DataItem("IsBan")) Then
100: Ban_Button1.Enabled = True
101: UnBan_Button1.Enabled = False
102: Ban_Button1.ForeColor = Drawing.Color.Red
103: Else
104: If Not e.Row.DataItem("IsBan") Then
105: Ban_Button1.Enabled = True
106: UnBan_Button1.Enabled = False
107: Ban_Button1.ForeColor = Drawing.Color.Red
108: Else
109: Ban_Button1.Enabled = False
110: UnBan_Button1.Enabled = True
111: UnBan_Button1.ForeColor = Drawing.Color.Red
112: End If
113: End If
114:
115: Dim UserNameColumns As HyperLink = CType(e.Row.FindControl("UserNameColumns"), HyperLink)
116: UserNameColumns.NavigateUrl = "http://" & ConfigurationManager.AppSettings("HostingURL")
117: End If
118: End Sub
119:
120: Protected Sub Ban_Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
121: Try
122: Dim UserID As String = CType(sender, LinkButton).CommandArgument
123: Dim BanUser As New ExecMySQL_RDR("id", UserID)
124: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = BanUser.ExecMySQL("Update releasebeat.aspnet_users set IsBan=True where id=@id", Data.CommandType.Text)
125: Refresh()
126: Catch ex As Exception
127: Lerr1.Text = ex.Message
128: End Try
129:
130: End Sub
131:
132: Protected Sub UnBan_Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
133: Try
134: Dim UserID As String = CType(sender, LinkButton).CommandArgument
135: Dim BanUser As New ExecMySQL_RDR("id", UserID)
136: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = BanUser.ExecMySQL("Update releasebeat.aspnet_users set IsBan=NULL where id=@id", Data.CommandType.Text)
137: Refresh()
138: Catch ex As Exception
139: Lerr1.Text = ex.Message
140: End Try
141: End Sub
142:
143: Protected Sub SetFilter_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SetFilter.Click
144: Session("admin_user_list_filter") = FilterBox.Text
145: Refresh()
146: End Sub
147:
148:
149: End Class
Следующая форма admin_user_list.aspx - это тоже в сущности запись одного бита в таблицу учета пользователей - только здесь есть еще сервис для отбора пользователей (когда их становятся тысячи и десятки тысяч): |
1: <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
2:
3: <asp:HiddenField ID="CurrentFields" runat="server" />
4: <asp:HiddenField ID="CurrentDirection" runat="server" />
5:
6: <h4>Забанить/разбанить пользователя</h4>
7: <asp:TextBox ID="FilterBox" runat="server"></asp:TextBox>
8: <asp:Button ID="SetFilter" runat="server" Text="Отфильтровать" />
9: <br><br>
10: <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" PageSize="25" Width="100%" CellPadding="5">
11: <Columns>
12: <asp:BoundField DataField="i" HeaderText="i" SortExpression="i" />
13: <asp:TemplateField>
14: <ItemTemplate>
15: <asp:LinkButton ID="Ban_Button1" runat="server"
16: CommandArgument='<%# Eval("id")%>' CommandName="Ban"
17: onclick="Ban_Button1_Click" >Забанить</asp:LinkButton>
18: <asp:LinkButton ID="UnBan_Button1" runat="server"
19: CommandArgument='<%# Eval("id")%>' CommandName="UnBan"
20: onclick="UnBan_Button1_Click" >Разбанить</asp:LinkButton>
21: </ItemTemplate>
22: </asp:TemplateField>
23: <asp:TemplateField HeaderText="UserName" SortExpression="UserName">
24: <ItemTemplate>
25: <asp:HyperLink ID="UserNameColumns" runat="server" Text='<%# Eval("UserName") %>' ></asp:HyperLink>
26: </ItemTemplate>
27: </asp:TemplateField>
28: <asp:CheckBoxField DataField="IsActivate" HeaderText="IsActivate" SortExpression="IsActivate" />
29: <asp:CheckBoxField DataField="IsAdmin" HeaderText="IsAdmin" SortExpression="IsAdmin" />
30: <asp:CheckBoxField DataField="IsBan" HeaderText="IsBan" SortExpression="IsBan" />
31: <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email" />
32: <asp:BoundField DataField="IP" HeaderText="IP" SortExpression="IP" />
33: <asp:BoundField DataField="CrDate" HeaderText="CrDate" SortExpression="CrDate" DataFormatString="{0:dd/MM/yyyy}" HtmlEncode="False" />
34: </Columns>
35: </asp:GridView>
36: <asp:Label ID="Lerr1" runat="server" ForeColor="#CC3300" Text=""></asp:Label>
37:
38:
39: </asp:Content>
40:
1: Partial Class admin_audio_ban
2: Inherits BasePage
3:
4: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
5: If Not IsPostBack Then
6: Refresh()
7: End If
8: End Sub
9:
10: Sub Refresh()
11: Try
12: Dim CreateAudio As New ExecMySQL_RDR()
13: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = CreateAudio.ExecMySQL("select * from releasebeat.audio", Data.CommandType.Text)
14: Dim DT1 As New Data.DataTable("Track")
15: DT1.Load(DR1)
16: GridView1.DataSource = DT1
17: GridView1.DataBind()
18: Catch ex As Exception
19: Lerr1.Text = ex.Message
20: End Try
21: End Sub
22:
23: Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
24: GridView1.PageIndex = e.NewPageIndex
25: Refresh()
26: End Sub
27:
28:
29: Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
30: If e.Row.DataItem IsNot Nothing Then
31: Dim UnBan_Button1 As LinkButton = CType(e.Row.FindControl("UnBanButton"), LinkButton)
32: Dim Ban_Button1 As LinkButton = CType(e.Row.FindControl("BanButton"), LinkButton)
33: If IsDBNull(e.Row.DataItem("IsBan")) Then
34: Ban_Button1.Enabled = True
35: UnBan_Button1.Enabled = False
36: Ban_Button1.ForeColor = Drawing.Color.Red
37: Else
38: If Not e.Row.DataItem("IsBan") Then
39: Ban_Button1.Enabled = True
40: UnBan_Button1.Enabled = False
41: Ban_Button1.ForeColor = Drawing.Color.Red
42: Else
43: Ban_Button1.Enabled = False
44: UnBan_Button1.Enabled = True
45: UnBan_Button1.ForeColor = Drawing.Color.Red
46: End If
47: End If
48: End If
49: End Sub
50:
51: Protected Sub BanButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)
52: Dim ID As String = CType(sender, LinkButton).CommandArgument
53: Try
54: Dim DeleteAudio As New ExecMySQL_RDR("id1", ID)
55: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = DeleteAudio.ExecMySQL("update releasebeat.audio set IsBan=True where id=@id1", Data.CommandType.Text)
56: Refresh()
57: Catch ex As Exception
58: Lerr1.Text = ex.Message
59: End Try
60: End Sub
61:
62: Protected Sub UnBanButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)
63: Dim ID As String = CType(sender, LinkButton).CommandArgument
64: Try
65: Dim DeleteAudio As New ExecMySQL_RDR("id1", ID)
66: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = DeleteAudio.ExecMySQL("update releasebeat.audio set IsBan=NULL where id=@id1", Data.CommandType.Text)
67: Refresh()
68: Catch ex As Exception
69: Lerr1.Text = ex.Message
70: End Try
71: End Sub
72:
73: End Class
И, наконец, последняя форма админки, которую я опишу в этом OpenSource-коплекте для работы с MySQL в ASP-NET - это форма admin_clear_user.aspx, предназначенная для полной очистки базы от данных пользователя: |
1: <%@ Page Language="VB" MasterPageFile="~/M1.master" AutoEventWireup="false" CodeFile="admin_clear_user.aspx.vb" Inherits="admin_clear_user" %>
2:
3: <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
4: <h4>Полная очистка базы от всех данных пользователя</h4>
5:
6: <asp:TextBox ID="FilterBox" runat="server"></asp:TextBox>
7: <asp:Button ID="SetFilter" runat="server" Text="Отфильтровать" />
8:
9: <asp:GridView ID="GridView1" runat="server" AllowPaging="True"
10: AutoGenerateColumns="False" DataKeyNames="Id" PageSize="20">
11: <Columns>
12: <asp:TemplateField HeaderText="UserId" SortExpression="Id">
13: <EditItemTemplate>
14: <asp:Label ID="Label1" runat="server" Text='<%# Eval("Id") %>'></asp:Label>
15: </EditItemTemplate>
16: <ItemTemplate>
17: <asp:LinkButton ID="LinkClear" runat="server" onclick="LinkClear_Click">Очистить базу</asp:LinkButton>
18: <asp:HiddenField ID="HiddenField1" runat="server" />
19: </ItemTemplate>
20: </asp:TemplateField>
21: <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email" />
22: <asp:BoundField DataField="UserName" HeaderText="UserName"
23: SortExpression="UserName" />
24: <asp:BoundField DataField="CrDate" HeaderText="Создан"
25: SortExpression="CrDate" />
26: <asp:BoundField DataField="Name1" HeaderText="Name1"
27: SortExpression="Name1" />
28: <asp:BoundField DataField="Name2" HeaderText="Name2"
29: SortExpression="Name2" />
30: </Columns>
31: </asp:GridView>
32: <asp:Label ID="Lerr1" runat="server" ForeColor="#CC3300" Text=""></asp:Label>
33:
34:
35: </asp:Content>
36:
В сущности это тоже вызов одной MySQL-процедуры, которая и должна в соответствии со структурой контрейнсов почистить базу. На этой форме тоже реализован сервис йильтрации юзеров.
1:
2: Partial Class admin_clear_user
3: Inherits BasePage
4:
5:
6: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
7: If Not IsPostBack Then
8: If Session("admin_clear_user_filter") Is Nothing Then Session("admin_clear_user_filter") = ""
9: FilterBox.Text = Session("admin_clear_user_filter")
10: GridView1_DataBind()
11: End If
12: End Sub
13:
14: Sub GridView1_DataBind()
15: Try
16: Dim Filter As String = Session("admin_clear_user_filter")
17: Dim DV1 As Data.DataView '= GetAllUsers1.Select(New DataSourceSelectArguments)
18: Dim GetAllUsers2 As New ExecMySQL_RDR()
19: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = GetAllUsers2.ExecMySQL("select * from releasebeat.aspnet_users order by i", Data.CommandType.Text)
20: Dim DT1 As New Data.DataTable("aspnet_users")
21: DT1.Load(DR1)
22: DV1 = DT1.DefaultView
23: If Filter <> "" Then
24: DV1.RowFilter = "UserName like '*" & Filter & "*'"
25: End If
26: GridView1.DataSource = DV1
27: GridView1.DataBind()
28: Catch ex As Exception
29: Lerr1.Text = ex.Message
30: End Try
31:
32: End Sub
33:
34: Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
35: GridView1.PageIndex = e.NewPageIndex
36: GridView1_DataBind()
37: End Sub
38:
39: Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
40: If e.Row.DataItem IsNot Nothing Then
41: Dim LinkClear As LinkButton = CType(e.Row.FindControl("LinkClear"), LinkButton)
42: Dim UserGuid As String = CType(e.Row.DataItem, Data.DataRowView)("Id").ToString
43: Dim HiddenField1 As HiddenField = CType(e.Row.FindControl("HiddenField1"), HiddenField)
44: HiddenField1.Value = UserGuid.ToString
45: If CType(e.Row.DataItem, Data.DataRowView)("UserName") = ConfigurationManager.AppSettings("Admin_Login").ToString Then
46: LinkClear.Enabled = False
47: End If
48: End If
49: End Sub
50:
51: Protected Sub LinkClear_Click(ByVal sender As Object, ByVal e As System.EventArgs)
52: Dim LinkClear As LinkButton = CType(sender, LinkButton)
53: Dim HiddenFields1 As HiddenField = CType(LinkClear.Parent.FindControl("HiddenField1"), HiddenField)
54: Dim DV1 As Data.DataView
55: Try
56: 'ClearAllUserInfo.SelectParameters("Id1").DefaultValue = HiddenFields1.Value
57: 'DV1 = ClearAllUserInfo.Select(New DataSourceSelectArguments)
58: Dim ClearAllUserInfo2 As New ExecMySQL_RDR("Id1", HiddenFields1.Value)
59: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = ClearAllUserInfo2.ExecMySQL("ClearAllUserInfo", Data.CommandType.StoredProcedure)
60:
61: Catch X As System.Exception
62: If DV1 IsNot Nothing Then
63: If DV1.Count > 0 Then
64: Lerr1.Text = X.Message & vbCrLf & DV1(0)("ErrorMessage")
65: Else
66: Lerr1.Text = X.Message
67: End If
68: Else
69: Lerr1.Text = X.Message
70: End If
71: Exit Sub
72: End Try
73: lerr1.text = ""
74: GridView1_DataBind()
75: End Sub
76:
77: Protected Sub SetFilter_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SetFilter.Click
78: Session("admin_clear_user_filter") = FilterBox.Text
79: GridView1_DataBind()
80: End Sub
81:
82:
83: End Class
Теперь рассмотрим еще пару общих компонентов управления пользователями любого ASP.NET-сайта. Это задание для удаления неактивированных логинов, базовая страничка и общие потоки проекта от global.asax для создания неудаляемого админа и других общих задач.
К счастью, MySQL является более развитым, чем MS SQL - в частности задания SQL JOB у него входят в бесплатную комплектацию, а не стоят 7 тысяч долларов, как у билогейтсовского сервера. Поэтому вы можете просто сконфигурировать SqlJob непосредственно в оснастке управления MySQL и удалять там неактивированные логины. Все это уже неоднократно и достаточно подробно разжевано у мня на сайте - Выполнение периодических задач в ASP.NET.
Базовые странички у меня тоже разжеваны до предела на моем сайте - читайте например Базовые странички ASP.NET. Ну а для этого OpenSource-шаблона я покажу какую-нибудь самую простую базовую страничку, которая в найпростейшем варианте может выглядеть вот так:
1: Imports Microsoft.VisualBasic
2:
3: Public Class BasePage
4: Inherits System.Web.UI.Page
5:
6: 'i INT(12) NOT NULL AUTO_INCREMENT,
7: 'id VARCHAR(36),
8: 'Email VARCHAR(50) NOT NULL,
9: 'Pass VARCHAR(50) NOT NULL,
10: 'ActivateID VARCHAR(36) NOT NULL,
11: 'IsActivate TINYINT(1) DEFAULT NULL,
12: 'CrDate DATETIME NOT NULL,
13: 'UserName VARCHAR(50) NOT NULL,
14: 'Name1 VARCHAR(50) DEFAULT NULL,
15: 'Name2 VARCHAR(50) DEFAULT NULL,
16: 'IP VARCHAR(16) NOT NULL,
17: 'IsAdmin TINYINT(1) DEFAULT NULL,
18:
19: Dim _User_I As Integer
20: Public ReadOnly Property User_I() As Integer
21: Get
22: Return _User_I
23: End Get
24: End Property
25:
26: Dim _User_id As String
27: Public ReadOnly Property User_id() As String
28: Get
29: Return _User_id
30: End Get
31: End Property
32:
33: Dim _User_Email As String
34: Public ReadOnly Property User_Email() As String
35: Get
36: Return _User_Email
37: End Get
38: End Property
39:
40: Dim _User_IsActivate As Boolean
41: Public ReadOnly Property User_IsActivate() As Boolean
42: Get
43: Return _User_IsActivate
44: End Get
45: End Property
46:
47: Dim _User_UserName As String
48: Public ReadOnly Property User_UserName() As String
49: Get
50: Return _User_UserName
51: End Get
52: End Property
53:
54: Dim _User_IsAdmin As Boolean
55: Public ReadOnly Property User_IsAdmin() As Boolean
56: Get
57: Return _User_IsAdmin
58: End Get
59: End Property
60:
61: Dim _User_Pass As String
62: Public ReadOnly Property User_Pass() As String
63: Get
64: Return _User_Pass
65: End Get
66: End Property
67:
68: Private Sub BasePage_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
69:
70: If HttpContext.Current.User.Identity.IsAuthenticated Then
71: 'If Session("UserPropertyExists") Is Nothing Then
72: 'аутенфицированный юзер, но свойства его еще не загружены в контекст странички
73: Dim GetOneUser As New ExecMySQL_RDR("Email", HttpContext.Current.User.Identity.Name)
74: Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = GetOneUser.ExecMySQL("select * from releasebeat.aspnet_users where email=@email", Data.CommandType.Text)
75: If DR1.Read Then
76: Session("UserPropertyExists") = "OK"
77: _User_I = DR1("I")
78: _User_id = DR1("id")
79: _User_Email = DR1("Email")
80: _User_UserName = DR1("UserName")
81: _User_Pass = DR1("Pass")
82: _User_IsActivate = DR1("IsActivate")
83: _User_IsAdmin = DR1("IsAdmin")
84:
85: End If
86: 'End If
87: End If
88: End Sub
89:
90: End Class
Все странички проекта наследуются от базовой странички вот так:
1: Partial Class Cab
2: Inherits BasePage
3:
4: Protected Sub Cab_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
5: Try
6: 'тут код странички
7: Catch ex As Exception
8: Lerr1.Text = ex.Message
9: End Try
10:
11:
12: End Sub
13: End Class
И тогда на каждой страничке проекта автоматически видно - в залогиненном ли контексте она вызывается (и кем именно) или в анонимном.
|