Archive for the ‘Web Back-end’ Category
-
转载:IIS FastCGI PHP 环境下搭建 WordPress
看到 Jerry Tao 在其博客上发表了一篇如何配置IIS7+FastCGI的文章,特转载过来学习。
Windows Server 2008 (SP2) + IIS 7
添加 Web 服务器角色,需要安装 CGI 扩展支持。
-
配置ASP.NET中使用SQL Server模式的Session State
作者通过亲自试验,完成了在Plesk平台下的SQLServer模式会话状态的配置。具体步骤如下:
- 为回话状态建立或是选择相应的数据库Database(Create New Database)
- 执行会话状态模板SQL语句
首先进入文件夹C:\Windows\Microsoft.NET\Framework\version_ID\,对于ASP.NET 2.0来说,一般version_ID是v2.0.50727。然后找到InstallSqlStateTemplate.sql,并将文中所有DatabaseNamePlaceHolder替换为你自己的数据库名称,最后将此SQL拖到数据库上执行 - 此时也许你会发现,测试SQL语句没问题,但是执行的时候出现了一些问题如下:
————————————————-
Starting execution of InstallSqlStateTemplate.SQL
————————————————-
————————————————–
Note:
This file is included for backward compatibility
only. You should use aspnet_regsql.exe to install
and uninstall SQL session state.
Run ‘aspnet_regsql.exe -?’ for details.
————————————————–
If the job does not exist, an error from msdb.dbo.sp_delete_job is expected.
Msg 229, Level 14, State 5, Procedure sp_delete_job, Line 1
The EXECUTE permission was denied on the object ‘sp_delete_job’, database ‘msdb’, schema ‘dbo’.
If the category already exists, an error from msdb.dbo.sp_add_category is expected.
Msg 229, Level 14, State 5, Procedure sp_add_category, Line 1
The EXECUTE permission was denied on the object ‘sp_add_category’, database ‘msdb’, schema ‘dbo’.
Msg 229, Level 14, State 5, Procedure sp_add_job, Line 1
The EXECUTE permission was denied on the object ‘sp_add_job’, database ‘msdb’, schema ‘dbo’.
————————————————–
Completed execution of InstallSqlStateTemplate.SQL
————————————————– - 更新web.config文件:
<sessionState mode=“SQLServer” allowCustomSqlDatabase=“true” sqlConnectionString=“data source=localhost;initial catalog=数据库名;user id=用用户名;password=密码” cookieless=“false” timeout=“20” />
不必担心,这个主要是由于用户权限不够而不能将某些规划任务加入到数据库计划中。我们无法将过期的一些session数据删除,不过可以手动操作,或是请求你的主机运营商帮忙
Reference:
-
浅谈ASP.net中使用WebServices的安全性保证
在开发一些在线业务的时候,对于一些客户端程序,我们需要将数据存储在网络上,即使用传统的C/S结构。随着WebServices的出现,我们可以用很低的成本在成熟的网络上架构这种结构,不必单独去购买数据中心服务器了。
实现的方法主要是:购建一个支持asp.net 2.0以上版本的虚拟服务器,然后在上面部署WebServices环境,通过调用asmx的方法对后台的数据库(MySQL、MS-SQL、Access等)进行数据库访问。而在客户端方面,我们就可以使用窗体了而不是Browser。通过调用后台的Services完成数据的交换。
数据交换容易,搭建WebServices也不是一件难事。但是难点在于,我们如何在这种基于HTTP下(没有SSL和证书)、透明的WebServices下,来保证Services的安全性?现在世面上的虚拟主机空间都不支持https。如何快速开发一个小DataServices呢?当然,我们第一步的考虑肯定是在每一个Service里面加上两个额外的参数:用户名和密码。这个可行,但是复杂度增加不少;后来我也考虑过使用Session来做。但是这种方法,只能适合在浏览器上的测试;而对于实际的客户端程序来讲,无疑没有什么作用。
通过学习,我掌握了一种在SOAP头中增加身份信息描述的方法;在客户端,只需要保存一个相关的身份验证对象,每次调用Services的时候就可以不必去考虑身份的问题了。Stub端会将身份信息绑定到SOAP Head中。
每次访问服务器,便会触发一个HttpModule来对身份进行验证。在Services体中,我们只需要判断是否已经通过身份验证即可。
首先我们要构造这个HttpModule。这是一个继承了IHttpModule接口的类,用来截获来自客户端的XML文件,并对其SOAP Head进行解析,找出我们需要的用户名和密码的信息,并交由WebServiceAuthenticationEventHandler所触发的事件来去判断身份。
using System; using System.Web; using System.IO; using System.Xml; using System.Xml.XPath; using System.Text; using System.Web.Services.Protocols; namespace JingZhiWebService { public sealed class WebServiceAuthenticationModule : IHttpModule { private WebServiceAuthenticationEventHandler _eventHandler = null; public event WebServiceAuthenticationEventHandler Authenticate { add { _eventHandler += value; } remove { _eventHandler -= value; } } public void Dispose() { } public void Init(HttpApplication app) { app.AuthenticateRequest += new EventHandler(this.OnEnter); } private void OnAuthenticate(WebServiceAuthenticationEvent e) { if (_eventHandler == null) return; _eventHandler(this, e); if (e.User != null) e.Context.User = e.Principal; } public string ModuleName { get { return "WebServiceAuthentication"; } } void OnEnter(Object source, EventArgs eventArgs) { HttpApplication app = (HttpApplication)source; HttpContext context = app.Context; Stream HttpStream = context.Request.InputStream; // Save the current position of stream. long posStream = HttpStream.Position; // If the request contains an HTTP_SOAPACTION // header, look at this message. if (context.Request.ServerVariables["HTTP_SOAPACTION"] == null) return; // Load the body of the HTTP message // into an XML document. XmlDocument dom = new XmlDocument(); string soapUser; string soapPassword; try { dom.Load(HttpStream); // Reset the stream position. HttpStream.Position = posStream; // Bind to the Authentication header. soapUser = dom.GetElementsByTagName("User").Item(0).InnerText; soapPassword = dom.GetElementsByTagName("Password").Item(0).InnerText; } catch (Exception e) { // Reset the position of stream. HttpStream.Position = posStream; // Throw a SOAP exception. XmlQualifiedName name = new XmlQualifiedName("Load"); SoapException soapException = new SoapException( "Unable to read SOAP request", name, e); throw soapException; } // Raise the custom global.asax event. OnAuthenticate(new WebServiceAuthenticationEvent (context, soapUser, soapPassword)); return; } } }接着是身份验证的事件。这个事件继承了EventArgs,并增加了相应的用户名密码字段。
using System; using System.Web; using System.Security.Principal; namespace JingZhiWebService { public delegate void WebServiceAuthenticationEventHandler(Object sender, WebServiceAuthenticationEvent e); public class WebServiceAuthenticationEvent : EventArgs { private System.Security.Principal.IPrincipal _IPrincipalUser; private HttpContext _Context; private string _User; private string _Password; public WebServiceAuthenticationEvent(HttpContext context) { _Context = context; } public WebServiceAuthenticationEvent(HttpContext context, string user, string password) { _Context = context; _User = user; _Password = password; } public HttpContext Context { get { return _Context; } } public IPrincipal Principal { get { return _IPrincipalUser; } set { _IPrincipalUser = value; } } public void Authenticate() { GenericIdentity i = new GenericIdentity(User); this.Principal = new GenericPrincipal(i, new String[0]); } public void Authenticate(string[] roles) { GenericIdentity i = new GenericIdentity(User); this.Principal = new GenericPrincipal(i, roles); } public string User { get { return _User; } set { _User = value; } } public string Password { get { return _Password; } set { _Password = value; } } public bool HasCredentials { get { if ((_User == null) || (_Password == null)) return false; return true; } } } }我们可以看到,通过触发这个事件,就可以对用户身份进行确认了,进而触发Authenticate()方法,来对身份进行登记。
当然,我们还需要一个属性框架来存放这个身份。这个类当然必须需要可以序列化(Serializable)来实现数据的传递。
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.Services.Protocols; namespace JingZhiWebService { public class WebServiceAuthentication : SoapHeader { public string User; public string Password; public WebServiceAuthentication() { } public WebServiceAuthentication(string user, string password) { this.User = user; this.Password = password; } } }为了能够让这个模块正常工作,我们必须要在Web.Config里面声明它。将下述代码放到system.web下:
<httpModules>
<add type=“JingZhiWebService.WebServiceAuthenticationModule” name=“WebServiceAuthentication”/>
</httpModules>最后,在Global.asax中来触发这个身份验证的事件。需要说明的是,事件绑定的时间不应该处于Application_Start时。那个时候Module还没有启动,所以在这个时候,我们无法取得到我们的Module运行时对象,事件的绑定也就无从谈起。经过测试,放在Application_BeginRequest是个不错的选择。
protected void Application_BeginRequest(object sender, EventArgs e) { WebServiceAuthenticationModule wam = (WebServiceAuthenticationModule)this.Modules["WebServiceAuthentication"]; wam.Authenticate += new WebServiceAuthenticationEventHandler(wam_Authenticate); } /// /// User Validation Process /// /// /// void wam_Authenticate(object sender, WebServiceAuthenticationEvent e) { if (e.User == "putyourusernamehere" && e.Password == "putyourpasswordhere") { e.Authenticate(new string[]{"user"}); } }通过上述的身份验证,我们就可以使用带有身份识别的Services了。
来看个例子如何使用身份识别。
using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; namespace JingZhiWebService { [WebService(Namespace = "http://www.techwork.cn/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ToolboxItem(false)] public class DataService : System.Web.Services.WebService { public WebServiceAuthentication authentication; private string UserRole = "user"; [WebMethod] [SoapHeader("authentication")] public bool UserAuthentication() { if (User.IsInRole(UserRole)) { return true; } return false; } } }那么客户端呢?
public static bool Authentication(string username, string password) { JingZhiDataService.WebServiceAuthentication auth = new JingZhi.JingZhiDataService.WebServiceAuthentication(); auth.User = username; auth.Password = password; ds.WebServiceAuthenticationValue = auth; return ds.UserAuthentication(); }我们可以在类中保存这个ds对象。每次调用WebServices的时候,直接用已经进行过身份认证的,绑定了user和password的DataService对象来调用服务。至此,我们完成了身份验证与Services的绑定。身份的问题不再是一个烫手的山芋那般不好处理了。
这种方式,对于一般的要求不是太高的个人和小型企业的业务,是个不错的选择。
最后我们再来看看实际的SOAP包是什么样子的吧。红色的部分,则是我们通过努力实现的身份验证。可以看到,我们已经将他们放入了SOAP Head中。
Request部分:
<?xml version=“1.0″ encoding=“utf-8″?>
<soap12:Envelope xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=“http://www.w3.org/2001/XMLSchema” xmlns:soap12=“http://www.w3.org/2003/05/soap-envelope”>
<soap12:Header>
<WebServiceAuthentication xmlns=“http://www.techwork.cn/”>
<User>string</User>
<Password>string</Password>
</WebServiceAuthentication>
</soap12:Header>
<soap12:Body>
<UserAuthentication xmlns=“http://www.techwork.cn/” />
</soap12:Body></soap12:Envelope>
Response部分:
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length<?xml version=“1.0″ encoding=“utf-8″?>
<soap12:Envelope xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=“http://www.w3.org/2001/XMLSchema” xmlns:soap12=“http://www.w3.org/2003/05/soap-envelope”>
<soap12:Body>
<UserAuthenticationResponse xmlns=“http://www.techwork.cn/”>
<UserAuthenticationResult>boolean</UserAuthenticationResult>
</UserAuthenticationResponse>
</soap12:Body>
</soap12:Envelope>综上,我们至此完成了用户名和密码的传输工作。
还有一个问题:http协议是明文传输的,那么我怎样保证用户名密码不被截获呢?答案是:不可能。对于我们来讲,还可以做的,是将我们的用户名密码加密。对于用户名,可以使用一种可回溯的明文加密方法;对于密码,建议直接选择MD5或者SHA1吧。System.Security.Cryptography命名空间下有MD5和SHA1的加密方法。这个到哪都能照出来,我也搜了一下,可以直接使用了:
当然,我们也可以使用Web.Config里面的Form认证方式。使用FormsAuthentication.HashPasswordForStoringInConfigFile()函数可以判断。这里就不再赘述了。
以高效率、低成本部署拥有足够安全性和灵活性的网络应用程序,是一种不错的选择。
-
小程序
用了近三个晚上开发了一个小程序——“精致三面翻”售出存档表,主要帮助我爸的公司进行数据整理。用到了ASP.net 2.0的技术。
虽然程序很小,但是相信对于父亲的公司还是挺有帮助的。开发过程中有一些小体会和经验:
- 程序并不是代码越优美越好。对于一些小程序,快速开发,省略一些无关紧要的问题显得非常重要。对于软件工程科班出身的我,编码时命名很难不想到匈牙利命名法。。如果我们把时间都花在校正变量上,那么无异于浪费。我的策略:将主要用到的TextBox/DateTimePicker等一些类的对象加以合理命名,其它的则随系统的自身命名好了。另外数据库选用了Access,表名、字段名全部中文。。加上.net 2.0的DataSet,开发非常快捷。。时间多半花在了画界面上。。
- 如果程序中出现几个大块相同的地方,建议把他们做成UserControl加以调用。省时省力。
- 如果你使用的是Access数据库,在进行参数传递的时候,变量名不要是SqlServer中的“select * from table where username=@username”,而应该是:“select * from table where username=?”。问号足矣。这点也花了我一定的时间。
- 对于.net的数据库,配置文件对它的路径描述是:|DataDirectory|。那么我们怎么找到这个文件夹呢?答案是:Application.LocalUserAppDataPath。这个有的时候很重要。。比如在我的备份功能那块。。
- 利用.net framwork 2.0发送mail的代码不用找了,我提供一个能用于gmail的,放在下面了。
- IconWorkshop软件做出来的icon很好看!
- That’s it. ^_^
public void SMTP(string from, string to, string bcc, string subject, string body, string attachment) { MailMessage mailMsg = new MailMessage(); mailMsg.From = new MailAddress(from); mailMsg.To.Add(to); mailMsg.Subject = subject; mailMsg.IsBodyHtml = true; mailMsg.BodyEncoding = Encoding.UTF8; mailMsg.Body = body; mailMsg.Attachments.Add(new Attachment(attachment)); mailMsg.Priority = MailPriority.Normal; // Smtp configuration SmtpClient client = new SmtpClient(); client.Credentials = new NetworkCredential("xxx@gmail.com", "thepassword"); client.Port = 587; //or use 465 client.Host = "smtp.gmail.com"; client.EnableSsl = true; object userState = mailMsg; try { //you can also call client.Send(msg) client.SendAsync(mailMsg, userState); client.SendCompleted += new SendCompletedEventHandler(client_SendCompleted); } catch (SmtpException ex) { //Catch errors... MessageBox.Show("Error:" + ex.Message); toolStripStatusLabel1.Text = "Error..."; this.Enabled = true; }
Paul’s Online Services
Dynamic Tag Cloud
WP Cumulus Flash tag cloud by Roy Tanck and Luke Morton requires Flash Player 9 or better.
Recent Posts
- AIX Storage Learning 1
- 春节快乐! Happy Spring Festival!
- Sun is to the end of life
- 为cos-html-cache插件增加页面(Page)、标签(Tag)和分类(Category)的静态化功能
- How to configure Subversion in OpenSolaris
- 转载:IIS FastCGI PHP 环境下搭建 WordPress
- 在OpenSolaris下动态绑定域名
- Goodbye 2009, Hello 2010
- This Is It
- A Morse Code Exchanger
Recent Comments
- 新视界 (New Vision) » 在OpenSolaris下动态绑定域名 on 使用ZFS打造家庭廉价数据中心
- paul on Wordpress数据库转移网址变换的方法
- 知识 on Wordpress数据库转移网址变换的方法
- WP Super Cache V0.98 and IIS7 « Anders Heie on Speed up your WordPress Blog on IIS 7 by using WP-Super-Cache
- 博沈 on This Is It
- paul on 使用ZFS打造家庭廉价数据中心
- Anonymous on OpenSolaris 上的 Samba 服务器
- Anonymous on 使用ZFS打造家庭廉价数据中心
- Anonymous on OpenSolaris 上的 Samba 服务器
- Paul on 十年前和十年后的我们