基于身份验证票据的权限系统的实现之源代码篇

前天的承诺,放出一个源代码。是现写的,时间比较仓促,取其精华,弃其糟粕吧。
还是一样,希望大家提出宝贵意见。

 
上一篇文章中提到了基于用户凭据的权限控制方法,今天向大家介绍如何基于这种方法开法应用程序。在这些源代码中,我们基于每个字节代表一种权限位的算法。
1、 建立数据库。
CREATE TABLE [dbo].[ 用户表 ](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [ 用户名 ] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,
    [ 用户密码 ] [char](32) COLLATE Chinese_PRC_CI_AS NULL,
    [ 用户权限 ] [binary](50) NULL
) ON [PRIMARY]
 
CREATE TABLE [dbo].[ 权限对照表 ](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [ 权限名称 ] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL
) ON [PRIMARY]
 
为了方便起见。今天只向大家介绍用户表和权限对照表。角色表暂不涉及
 
2、  创建 DataAccess 类。大家可能习惯于使用 SqlHelper 。我比较喜欢自己写一个小类。萝卜青菜,各有所爱吧。
using System;
using System.Data;
using System.Data.SqlClient;
 
namespace localhost
{
     ///<summary>
     /// 数据库处理组件
     ///</summary>
     public class DataAccess
     {
         public SqlConnection Connection
         {
              get{return _conn;}
              set{_conn = value;}
         }
         private SqlConnection _conn;
         public DataAccess()
         {
              string connectString = System.Configuration.ConfigurationSettings.AppSettings["connectstring"];
              this._conn = new SqlConnection(connectString);
         }
         public DataAccess(string connectString)
         {
              this._conn = new SqlConnection(connectString);
         }
 
         public void OpenConnection()
         {
              if(this._conn != null && this._conn.State == ConnectionState.Closed)
                   this._conn.Open();
              else if(this._conn == null)
                   throw new Exception("Connection 还没有初始化");
         }
         public void CloseConnection()
         {
              if(this._conn != null && this._conn.State == ConnectionState.Open)
                   this._conn.Close();
              else if(this._conn == null)
                   throw new Exception("Connection 还没有初始化");
         }
 
         public SqlDataReader ExecuteReader(string sql,params SqlParameter[] parameters)
         {
              SqlCommand command = new SqlCommand(sql);
              return ExecuteReader(command,parameters);
         }
         public SqlDataReader ExecuteReader(SqlCommand command,params SqlParameter[] parameters)
         {
              foreach(SqlParameter parameter in parameters)
              {
                   command.Parameters.Add(parameter);
              }
              return ExecuteReader(command);
         }
         public SqlDataReader ExecuteReader(SqlCommand command)
         {
              command.Connection = this._conn;
              this.OpenConnection();
 
              return command.ExecuteReader();
         }
         public int ExecuteNonQuery(string sql,params SqlParameter[] parameters)
         {
              SqlCommand command = new SqlCommand(sql);
              return ExecuteNonQuery(command,parameters);
         }
         public int ExecuteNonQuery(SqlCommand command,params SqlParameter[] parameters)
         {
              for(int i = 0; i < parameters.Length ; i++)
                   command.Parameters.Add(parameters[i]);
              return ExecuteNonQuery(command);
         }
         public int ExecuteNonQuery(SqlCommand command)
         {
              command.Connection = this._conn;
              this.OpenConnection();
              try
              {
                   return command.ExecuteNonQuery();
              }
              finally
              {
                   this.CloseConnection();
              }
         }
         public int FillDataSet(DataSet dataset,SqlCommand command,string tablename)
         {
              command.Connection = this._conn;
              try
              {
                   this.OpenConnection();
                   SqlDataAdapter adapter = new SqlDataAdapter(command);
                   return adapter.Fill(dataset,tablename);
              }
              finally
              {
                   this.CloseConnection();
              }
         }
         public int FillDataSet(DataSet dataset,string sql,string tablename,params SqlParameter[] parameters)
         {
              SqlCommand command = new SqlCommand(sql);
              return this.FillDataSet(dataset,command,tablename,parameters);
         }
         public int FillDataSet(DataSet dataset,SqlCommand command,string tablename,params SqlParameter[] parameters)
         {
              foreach(SqlParameter parameter in parameters)
                   command.Parameters.Add(parameter);
              return this.FillDataSet(dataset,command,tablename);
         }
     }
}
 
3、   创建登录类LoginClass。这个类也可以直接写到登录页面中。为了方便,我们把权限的长度写为50位长。并且每个字节表示一种权限。做为一个常量保存在类中,名字是Length。该类提供了一个静态方法Login,输入用户名和密码,返回一个Ticket。如果失败则抛出异常。我们并没有处理此异常。在实际的应用中大家可以根据自己的需要处理此异常。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.Security;
 
namespace localhost
{
     ///<summary>
     /// 登录组件
     ///</summary>
     public class LoginClass
     {
         // 定义权限列的长度
         public const int Length = 50;
         public LoginClass()
         {
             
         }
 
         public static FormsAuthenticationTicket Login(string username,string password)
          {
              string sql = "SELECT TOP 1 * FROM 用户表 WHERE 用户名 = @username";//取出用户输入用户名的用户信息
 
              SqlParameter userParameter = new SqlParameter("@username",username); // 将用户名作为参数传入,避免SQL注入的发生
 
              DataAccess da = new DataAccess();// 实例化数据访问组件
 
              try
              {
                   SqlDataReader reader = da.ExecuteReader(sql,userParameter); // 执行SQL语句,返回一个SqlDataReader
                   if(reader.Read())// 如果读取到了数据
                   {
                       if(reader[" 用户密码"] == null || (string)reader["用户密码"] != HashPassWord(password)) //如果用户密码为null或与数据库中保存的不一致
                            throw new Exception(" 用户密码不正确");//密码错误,抛出异常
 
                       byte[] buffer = new byte[Length]; // 定义一个与权限字节长度相等的字节数组
                       int index = reader.GetOrdinal(" 用户权限");//取出用户权限列对应的序号
                       if(!reader.IsDBNull(index)) // 如果用户权限这一列不为null。则取出来保存到字节数组中
                            reader.GetBytes(index,0,buffer,0,buffer.Length);
 
                       string userdata = string.Empty;
                       foreach(byte b in buffer)
                            userdata += Convert.ToString(b,2).PadLeft(1,'0'); // 转成0与1组成的字符串
 
                       FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,username,DateTime.Now,DateTime.MaxValue,false,userdata); // 把这些信息保存到一个Ticket中
                       return ticket;
                   }
                   else
                       throw new Exception(" 用户不存在");//抛出用户名不存在的异常
              }
              finally
              {
                   da.CloseConnection();// 断开数据库连接,实际的应用中。可以在读取完字节数组后就断开,我们使用数据库的原则是晚连早断。
              }
 
         }
         public static string HashPassWord(string password) // 计算密码的散列值
         {
              return FormsAuthentication.HashPasswordForStoringInConfigFile(password,"md5");
         }
     }
}
 
4、   创建一个继承自Page的类PageBase。需要验证的类都要继承自这个类,这样当页面初始化时。会首先执行此OnInit事件。即首先通过验证才能进行此页面的访问,在此操作中。我们对没有通过验证的用户,也直接抛出异常,实际情况可以自定义自己的操作。
using System;
using System.Web.Security;
 
namespace localhost
{
     ///<summary>
     /// 页面基类
     ///</summary>
     public class PageBase:System.Web.UI.Page
     {
         protected int[] _needPermissions; // 需要的权限列表。数组的每一个值表示权限表中的ID,大家可以重写它。直接写入权限名称。然后取出ID放在此数组中
         protected override void OnInit(EventArgs e)
         {
             
              // 验证权限
              if(this._needPermissions != null && this._needPermissions.Length > 0) // 当权限数组不是null并且长度大于0时,表示需要验证
              {
                   string userdata = string.Empty;
                   if(User.Identity.IsAuthenticated)
                   {
                       FormsIdentity identity = User.Identity as FormsIdentity;
                       userdata = identity.Ticket.UserData;
                   }
                   if(userdata == string.Empty) // 没有登录,抛出异常
                       throw new Exception(" 非法请求");
                   foreach(int index in this._needPermissions)
                   {
                       if(userdata.Length - 1 < index || userdata.Substring(index,1) == "0")
                            throw new Exception(" 非法请求");//没有权限,抛出异常
                   }
              }
              base.OnInit (e);
         }
 
     }
}
5、   创建一个登录页面Login.aspx。此页面主要有两个TextBox,分别用于输入用户名和密码。一个按钮,用户点击此按钮时开始登录
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Security;
 
namespace localhost
{
     ///<summary>
     /// 登录页面
     ///</summary>
     public class Login : System.Web.UI.Page
     {
         protected System.Web.UI.WebControls.Label Label1;
         protected System.Web.UI.WebControls.TextBox TextBox1;
         protected System.Web.UI.WebControls.Label Label2;
         protected System.Web.UI.WebControls.TextBox TextBox2;
         protected System.Web.UI.WebControls.Button Button1;
    
         private void Page_Load(object sender, System.EventArgs e)
         {
              // 在此处放置用户代码以初始化页面
         }
 
         #region Web 窗体设计器生成的代码
         override protected void OnInit(EventArgs e)
         {
              //
              // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
              //
              InitializeComponent();
              base.OnInit(e);
         }
        
         ///<summary>
         /// 设计器支持所需的方法 - 不要使用代码编辑器修改
         /// 此方法的内容。
         ///</summary>
         private void InitializeComponent()
         {   
              this.Button1.Click += new System.EventHandler(this.Button1_Click);
              this.Load += new System.EventHandler(this.Page_Load);
 
         }
         #endregion
 
         private void Button1_Click(object sender, System.EventArgs e)
         {
              string username = TextBox1.Text; // 用户名
              string password = TextBox2.Text; // 密码
 
              try
              {
                   FormsAuthenticationTicket ticket = LoginClass.Login(username,password); // 登录。如果成功的话会抛出异常。否则返回登录后的ticket
                   string data = FormsAuthentication.Encrypt(ticket); // 将ticket登录
 
                   HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,data); // 将加密后的ticket保存在Cookie中
                   Response.Cookies.Add(cookie);
                   string strRedirect = Request["ReturnUrl"];// 取出登录后返回的页面
                   if (strRedirect == null)
                       strRedirect = "Default.aspx";
                   Response.Redirect(strRedirect, true); // 返回
              }
              catch(Exception ex) // 捕获异常。弹出对话话提示用户登录失败
              {
                   Page.RegisterClientScriptBlock("alertloginerror","<script>alert(' 您输入的用户名或密码不正确');</script>");
              }
          }
     }
}
 
6、 创建一个授权页面WebForm1.aspx。这个页面用于给用户授权。有两个DropDownListBox。分别显示所有用户和所有权限。一个RadioButtonList。用于确定是授权还是取消此权限。为了使用方面,建议使用DataGrid来操作。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
 
namespace localhost
{
     ///<summary>
     /// WebForm2 的摘要说明。
     ///</summary>
     public class WebForm2 : PageBase
     {
         protected System.Web.UI.WebControls.DropDownList DropDownList2;
         protected System.Web.UI.WebControls.RadioButtonList RadioButtonList1;
         protected System.Web.UI.WebControls.Button Button1;
         protected System.Web.UI.WebControls.DropDownList DropDownList1;
    
         private void Page_Load(object sender, System.EventArgs e)
         {
              if(!IsPostBack)
              {
                   this.Bind_Users();
                   this.Bind_Permissions();
              }
         }
         private void Bind_Users()// 取出所有用户并绑定到DropDownList1
         {
              string sql = "SELECT 用户名 FROM 用户表";
              DataSet dataset = new DataSet();
              dataset.Tables.Add("users");
 
              DataAccess da = new DataAccess();
              da.FillDataSet(dataset,sql,"users");
 
              DropDownList1.DataSource = dataset.Tables[0].DefaultView;
              DropDownList1.DataTextField = " 用户名";
              DropDownList1.DataValueField = " 用户名";
 
              DropDownList1.DataBind();
 
         }
         private void Bind_Permissions()// 绑定所有权限
         {
              string sql = "SELECT ID, 权限名称 FROM 权限对照表";
              DataSet dataset = new DataSet();
              dataset.Tables.Add("permissions");
 
              DataAccess da = new DataAccess();
              da.FillDataSet(dataset,sql,"permissions");
 
              DropDownList2.DataSource = dataset.Tables[0].DefaultView;
              DropDownList2.DataTextField = " 权限名称";
              DropDownList2.DataValueField = "ID";
 
              DropDownList2.DataBind();
 
         }
 
         #region Web 窗体设计器生成的代码
         override protected void OnInit(EventArgs e)
         {
              //
              // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
              //
              InitializeComponent();
              base.OnInit(e);
         }
        
         ///<summary>
         /// 设计器支持所需的方法 - 不要使用代码编辑器修改
         /// 此方法的内容。
         ///</summary>
         private void InitializeComponent()
         {   
              this.DropDownList1.SelectedIndexChanged += new System.EventHandler(this.DropDownList1_SelectedIndexChanged);
              this.Button1.Click += new System.EventHandler(this.Button1_Click);
              this.Load += new System.EventHandler(this.Page_Load);
 
         }
 
         #endregion
 
 
         private void DropDownList1_SelectedIndexChanged(object sender, System.EventArgs e)
         {
        
         }
 
         private void Button1_Click(object sender, System.EventArgs e) // 给用户授权还是取消权限
         {
              string username = DropDownList1.SelectedValue; // 用户名
              DataAccess da = new DataAccess();// 实例化数据操作类
              SqlParameter user = new SqlParameter("@username",DropDownList1.SelectedValue); // 用户名参数
              SqlDataReader reader = da.ExecuteReader("SELECT TOP 1 用户权限 FROM 用户表 WHERE 用户名 = @username",user); //取回一个DataReader。包含用户权限
 
              byte[] buffer = new byte[LoginClass.Length]; // 定义一个字节数组保用用户现在的权限
              if(reader.Read() && !reader.IsDBNull(0))
                   reader.GetBytes(0,0,buffer,0,buffer.Length); // 将用户权限取出来保存到字节数组中
              da.CloseConnection();// 关闭数据连接
 
              int index = int.Parse(DropDownList2.SelectedValue); // 要处理的权限ID
 
            buffer[index] = RadioButtonList1.Items[0].Selected ? (byte)1:(byte)0; // 根据选择的授权还是取消授权。将字节数组中对应的位设置为1或0
 
              string sql = "UPDATE 用户表 SET 用户权限 = @permission WHERE 用户名=@user";//更新用户权限列
 
              SqlParameter parameter = new SqlParameter("@permission",SqlDbType.Binary,buffer.Length);
              parameter.Value = buffer; // 将字节数组作为参数传入SQL语句执行
 
              da.ExecuteNonQuery(sql,parameter,user);
 
 
         }
     }
}
 
7、 创建一个测试页面WebForm1.aspx。这个页面将_needPermissions数组赋为{1},即只需要权限表中ID为1的参数。由于这个页面的权限验证在其基类PageBase 中实现,所以不需要任何验证即拥有了权限验证功能。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
 
namespace localhost
{
     ///<summary>
     /// WebForm1 的摘要说明。
     ///</summary>
     public class WebForm1 : PageBase
     {
         public WebForm1()
         {
              base._needPermissions = new int[] {1};
         }
         private void Page_Load(object sender, System.EventArgs e)
         {
             
         }
 
         #region Web 窗体设计器生成的代码
         override protected void OnInit(EventArgs e)
         {
              //
              // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
              //
              InitializeComponent();
              base.OnInit(e);
         }
        
         ///<summary>
         /// 设计器支持所需的方法 - 不要使用代码编辑器修改
         /// 此方法的内容。
         ///</summary>
         private void InitializeComponent()
         {   
              this.Load += new System.EventHandler(this.Page_Load);
         }
         #endregion
     }
}
8、 修改Web.config 文件
< authentication mode ="Forms">
    <formsname=".ASPXFORMSDEMO"loginUrl="Logn.aspx" protection="All"path="/"timeout="30"/> Õ
 
</ authentication >
使用Forms认证。
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值