Archive for the ‘Web Back-end’ Category

  • 转载:IIS FastCGI PHP 环境下搭建 WordPress

    Date: 2010.01.12 | Category: Learn from Others, Web Back-end, WordPress | Response: 0

    看到 Jerry Tao 在其博客上发表了一篇如何配置IIS7+FastCGI的文章,特转载过来学习。

    Win­dows Server 2008 (SP2) + IIS 7
    添加 Web 服务器角色,需要安装 CGI 扩展支持。

    image

    Read the rest of this entry »

    • Share/Bookmark
  • 配置ASP.NET中使用SQL Server模式的Session State

    Date: 2009.09.18 | Category: Web Back-end | Response: 0

    作者通过亲自试验,完成了在Plesk平台下的SQLServer模式会话状态的配置。具体步骤如下:

    1. 为回话状态建立或是选择相应的数据库Database(Create New Database)
    2. 执行会话状态模板SQL语句
      首先进入文件夹C:\Windows\Microsoft.NET\Framework\version_ID\,对于ASP.NET 2.0来说,一般version_ID是v2.0.50727。然后找到InstallSqlStateTemplate.sql,并将文中所有Data­ba­se­Na­me­Pla­ce­Ho­lder替换为你自己的数据库名称,最后将此SQL拖到数据库上执行
    3. 此时也许你会发现,测试SQL语句没问题,但是执行的时候出现了一些问题如下:
      ————————————————-
      Sta­r­ting exe­cu­tion of InstallSqlStateTemplate.SQL
      ————————————————-

      ————————————————–
      Note:                                            
      This file is inclu­ded for backward compa­ti­bi­lity 
      only.  You should use aspnet_regsql.exe to install
      and unin­stall SQL session state.                 

      Run ‘aspnet_regsql.exe -?’ for details.        
      ————————————————–
      If the job does not exist, an error from msdb.dbo.sp_delete_job is expe­cted.
      Msg 229, Level 14, State 5, Pro­ce­dure sp_delete_job, Line 1
      The EXECUTE per­mi­ssion was denied on the object ‘sp_delete_job’, data­base ‘msdb’, schema ‘dbo’.
      If the cate­gory already exi­sts, an error from msdb.dbo.sp_add_category is expe­cted.
      Msg 229, Level 14, State 5, Pro­ce­dure sp_add_category, Line 1
      The EXECUTE per­mi­ssion was denied on the object ‘sp_add_category’, data­base ‘msdb’, schema ‘dbo’.
      Msg 229, Level 14, State 5, Pro­ce­dure sp_add_job, Line 1
      The EXECUTE per­mi­ssion was denied on the object ‘sp_add_job’, data­base ‘msdb’, schema ‘dbo’.

      ————————————————–
      Comple­ted exe­cu­tion of InstallSqlStateTemplate.SQL
      ————————————————–
    4. 不必担心,这个主要是由于用户权限不够而不能将某些规划任务加入到数据库计划中。我们无法将过期的一些session数据删除,不过可以手动操作,或是请求你的主机运营商帮忙

    5. 更新web.config文件:
      <session­State mode=“SQLServer” allowCustomSqlDatabase=“true” sqlConnectionString=“data source=localhost;initial catalog=数据库名;user id=用用户名;password=密码” cookieless=“false” timeout=“20” />

     

    Refe­rence:

    • Share/Bookmark
  • 浅谈ASP.net中使用WebServices的安全性保证

    Date: 2008.11.05 | Category: Programming Language, Web Back-end | Response: 0

    在开发一些在线业务的时候,对于一些客户端程序,我们需要将数据存储在网络上,即使用传统的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;
    }
    }
    }

    接着是身份验证的事件。这个事件继承了Even­tA­rgs,并增加了相应的用户名密码字段。

    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;
    }
    }
    }
    }

    我们可以看到,通过触发这个事件,就可以对用户身份进行确认了,进而触发Authen­ti­cate()方法,来对身份进行登记。

    当然,我们还需要一个属性框架来存放这个身份。这个类当然必须需要可以序列化(Seria­li­za­ble)来实现数据的传递。

    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下:

    <httpMo­du­les>
    <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"});
    }
    }

    通过上述的身份验证,我们就可以使用带有身份识别的Servi­ces了。

    来看个例子如何使用身份识别。

    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:Hea­der>
    <WebServi­ceAu­then­ti­ca­tion xmlns=“http://www.techwork.cn/”>
    <User>string</User>
    <Password>string</Password>
    </WebServiceAuthentication>
    </soap12:Header>
    <soap12:Body>
    <Use­rAu­then­ti­ca­tion 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>
    <Use­rAu­then­ti­ca­tion­Re­sponse xmlns=“http://www.techwork.cn/”>
    <UserAuthenticationResult>boolean</UserAuthenticationResult>
    </UserAuthenticationResponse>
    </soap12:Body>
    </soap12:Envelope>

    综上,我们至此完成了用户名和密码的传输工作。

    还有一个问题:http协议是明文传输的,那么我怎样保证用户名密码不被截获呢?答案是:不可能。对于我们来讲,还可以做的,是将我们的用户名密码加密。对于用户名,可以使用一种可回溯的明文加密方法;对于密码,建议直接选择MD5或者SHA1吧。System.Security.Cryptography命名空间下有MD5SHA1的加密方法。这个到哪都能照出来,我也搜了一下,可以直接使用了:

    当然,我们也可以使用Web.Config里面的Form认证方式。使用FormsAuthentication.HashPasswordForStoringInConfigFile()函数可以判断。这里就不再赘述了。

    以高效率、低成本部署拥有足够安全性和灵活性的网络应用程序,是一种不错的选择。

    • Share/Bookmark
  • 小程序

    Date: 2008.10.30 | Category: Programming Language, Web Back-end | Response: 1

    用了近三个晚上开发了一个小程序——“精致三面翻”售出存档表,主要帮助我爸的公司进行数据整理。用到了ASP.net 2.0的技术。

    image

    image image

    虽然程序很小,但是相信对于父亲的公司还是挺有帮助的。开发过程中有一些小体会和经验:

    • 程序并不是代码越优美越好。对于一些小程序,快速开发,省略一些无关紧要的问题显得非常重要。对于软件工程科班出身的我,编码时命名很难不想到匈牙利命名法。。如果我们把时间都花在校正变量上,那么无异于浪费。我的策略:将主要用到的TextBox/DateTimePicker等一些类的对象加以合理命名,其它的则随系统的自身命名好了。另外数据库选用了Access,表名、字段名全部中文。。加上.net 2.0的DataSet,开发非常快捷。。时间多半花在了画界面上。。
    • 如果程序中出现几个大块相同的地方,建议把他们做成User­Con­t­rol加以调用。省时省力。
    • 如果你使用的是Access数据库,在进行参数传递的时候,变量名不要是SqlServer中的“select * from table where username=@username”,而应该是:“select * from table where username=?”。问号足矣。这点也花了我一定的时间。
    • 对于.net的数据库,配置文件对它的路径描述是:|DataDirectory|。那么我们怎么找到这个文件夹呢?答案是:Application.LocalUserAppDataPath。这个有的时候很重要。。比如在我的备份功能那块。。
    • 利用.net fra­mwork 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;
    }
    • Share/Bookmark

Paul’s Online Services

Dynamic Tag Cloud

Recent Posts

Recent Comments

Tags

2008.11.Trip-of-GuangXi ASP.net C++ China Chrome css dotNet FCGuoAn Firefox Football gmail IBM IE IIS IT Association Joke Microsoft music mysql NLP Nokia ntfs NumPy OpenSolaris open source Open Team php pidgin PKUSS Python Python Challenge qq Samba SciPy Learning shell solaris SQL SUN Thunderbird Travel web host Win 7 WordPress X11 zfs