基于角色的安全在web应用有广泛的应用,在.net中对角色安全的支持分为三中
1:基于Windows的身份验证
2:基于表单的身份验证
3:基于Passport的身份验证
简单说一下第一种和第三种,基于Windows的身份验证是把安全交给Windows的安全
子系统,依靠域服务器和IIS,当一个请求到达时,IIS首先截获,请求域服务器,进行身份验证,生成访问钥匙,然后严格按照ACL(Access Control List),执行相应的权限。基于Windows的角色安全是用在局域网的(Intranet)。基于Web的(Internet)应用拥有大量用户的程序来说,维护一个庞大的ACL是不现实的,所以要使用基于表单的身份验证和基于Passport的身份验证,Passport的身份验证是MS提供的一个用来赚钱的服务,你要去订阅,他提供了很高的安全性和可跨站点的访问。基于表单的身份验证是最多的吧,我简单研究了一下,也对他进行了简单的实现。
有的解决方案是Context.User=new GenericPrinciple(“”,角色数组);但是这不能够解决权限问题(我想了很久),所以需要实现一个IPrinciple接口扩充负责者的功能。好了,先看一下数据库的设计:
一个RoleAuthentication_Account表,包括UserID,UserFriendName,UserName,Password字段用来存储用户信息,不用多说。
一个RoleAuthentication_Role表,包括RoleID,Description
一个RoleAuthentication_Permission,包括PermissionId,Description,
一个RoleAuthentication_AccountRole, RoleAuthentication_RolePermission,很简单完成多对多的应射。
好了接下来数据服务的程序:
RoleAuthenticationDAL.cs
using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Text;
using System.Security;
using System.Security.Cryptography;
namespace RoleAuthenticationDataAccessLayer
{
/// <summary>
/// Class1 的摘要说明。
/// </summary>
public class Account
{
public Account()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public DataRow getUserInfo(int UserID)
{
SqlParameter[] parameters = { new SqlParameter("@UserID", SqlDbType.Int) };
parameters[0].Value = UserID;
DataSet ds=DataAccessHelper.EexcuteDataSet(DataAccessHelper.ConStr,CommandType.StoredProcedure,"getUserInfo",parameters);
return ds.Tables[0].Rows[0];
}
public ArrayList getUserRole(int UserID)
{
ArrayList role=new ArrayList();
SqlParameter[] parameters = { new SqlParameter("@UserID", SqlDbType.Int) };
parameters[0].Value = UserID;
SqlDataReader dr = DataAccessHelper.ExecuteReader(DataAccessHelper.ConStr,CommandType.StoredProcedure,"getUserRole",parameters);
while(dr.Read())
{
role.Add(dr.GetInt32(0));
}
dr.Close();
return role;
}
public ArrayList getUserPermission(int UserID)
{
ArrayList role=new ArrayList();
SqlParameter[] parameters = { new SqlParameter("@UserID", SqlDbType.Int) };
parameters[0].Value = UserID;
SqlDataReader dr = DataAccessHelper.ExecuteReader(DataAccessHelper.ConStr,CommandType.StoredProcedure,"getUserPermission",parameters);
while(dr.Read())
{
role.Add(dr.GetInt32(0));
}
dr.Close();
return role;
}
public int Login(string UserName,string Password)
{
for(int i=0;i<15-UserName.Length;i++)
{
UserName+=" ";
}
byte[] pass=EncryptPassword(Password);
SqlParameter[] parameters = { new SqlParameter("@UserID", SqlDbType.Int),new SqlParameter("@UserName", SqlDbType.Char),new SqlParameter("@UserPassword", SqlDbType.VarBinary) };
parameters[0].Direction=ParameterDirection.Output;
parameters[1].Value = UserName;
parameters[2].Value=pass;
int result=DataAccessHelper.RExecutNonQuery(DataAccessHelper.ConStr,CommandType.StoredProcedure,"Login",parameters);
if(result>0)
{
return result;
}
else
{
return -1;
}
}
public static byte[] EncryptPassword(string password)
{
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] hashBytes = encoding.GetBytes( password );
// compute SHA-1 hash.
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] cryptPassword = sha1.ComputeHash ( hashBytes );
return cryptPassword;
}
public bool AddUser(string UserName,string UserFriendName,string Password)
{
for(int i=0;i<15-UserName.Length;i++)
{
UserName+=" ";
}
byte[] pass=EncryptPassword(Password);
SqlParameter[] parameters = { new SqlParameter("@UserName", SqlDbType.Char),new SqlParameter("@UserPassword", SqlDbType.VarBinary,20),new SqlParameter("@UserFriendName", SqlDbType.VarChar,50) };
parameters[0].Value = UserName;
parameters[1].Value=pass;
parameters[2].Value=UserFriendName;
if(DataAccessHelper.ExecutNonQuery(DataAccessHelper.ConStr,CommandType.StoredProcedure,"AddUser",parameters)>0)
{
return true;
}
else
{
return false;
}
}
public bool ContributeRoleForUser(int UserID,int RoleID)
{
SqlParameter[] parameters = { new SqlParameter("@UserID", SqlDbType.Int),new SqlParameter("@RoleID", SqlDbType.Int) };
parameters[0].Value = UserID;
parameters[1].Value=RoleID;
if(DataAccessHelper.ExecutNonQuery(DataAccessHelper.ConStr,CommandType.StoredProcedure,"ContributeRoleForUser",parameters)>0)
{
return true;
}
else
{
return false;
}
}
}
}
DataAccessHelper.cs这个简单的类是自己实现的在不知道有MS的DataAccess之前
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
namespace RoleAuthenticationDataAccessLayer
{
/// <summary>
/// DataAccessHelper 的摘要说明。
/// </summary>
public abstract class DataAccessHelper
{
public static readonly string ConStr="server=GOODBABY;database=PRRolesAuthentication;uid=sa;password=goodbaby";//ConfigurationSettings.AppSettings["ConnectionString"];
public static int ExecutNonQuery(string connString, CommandType cmdType, string cmdText, params SqlParameter[] cmdParms)
{
SqlCommand cmd=new SqlCommand();
SqlConnection con=new SqlConnection(connString);
PrepareCmd(cmd,con,cmdType,cmdText,cmdParms);
try
{
int result=cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
return result;
}
catch(Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
}
public static int RExecutNonQuery(string connString, CommandType cmdType, string cmdText, params SqlParameter[] cmdParms)
{
SqlCommand cmd=new SqlCommand();
SqlConnection con=new SqlConnection(connString);
PrepareCmd(cmd,con,cmdType,cmdText,cmdParms);
try
{
int result=-1;
cmd.ExecuteNonQuery();
if(cmd.Parameters[0].Value is DBNull)
{
return result;
}
result=Convert.ToInt32(cmd.Parameters[0].Value);
cmd.Parameters.Clear();
return result;
}
catch(Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
}
public static SqlDataReader ExecuteReader(string connString, CommandType cmdType, string cmdText, params SqlParameter[] cmdParms)
{
SqlCommand cmd=new SqlCommand();
SqlConnection con=new SqlConnection(connString);
PrepareCmd(cmd,con,cmdType,cmdText,cmdParms);
try
{
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch(SqlException ex1)
{
throw ex1;
}
}
public static DataSet EexcuteDataSet(string connString, CommandType cmdType, string cmdText, params SqlParameter[] cmdParms)
{
SqlCommand cmd=new SqlCommand();
SqlConnection con=new SqlConnection(connString);
PrepareCmd(cmd,con,cmdType,cmdText,cmdParms);
SqlDataAdapter dap=new SqlDataAdapter(cmd);
try
{
DataSet myDS=new DataSet();
dap.Fill(myDS);
return myDS;
}
catch(SqlException ex2)
{
throw ex2;
}
finally
{
con.Close();
}
}
private static void PrepareCmd(SqlCommand cmd, SqlConnection conn, CommandType cmdType, string cmdText, SqlParameter[] cmdParms)
{
if (conn.State != ConnectionState.Open)
conn.Open();
cmd.Connection = conn;
cmd.CommandText = cmdText;
cmd.CommandType=cmdType;
if (cmdParms != null)
{
foreach(SqlParameter SqlPar in cmdParms)
{
cmd.Parameters.Add(SqlPar);
}
}
}
}
}
在BL中实现了IPrinciple,IIdentity
using System;
using System.Security.Principal;
using System.Collections;
using RoleAuthenticationDataAccessLayer;
namespace RolsesAuthenticationBL
{
/// <summary>
/// Class1 的摘要说明。
/// </summary>
public class MyPrinciple:IPrincipal
{
protected IIdentity identity;
protected ArrayList permissionList;
protected ArrayList roleList;
public MyPrinciple()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
//use DataAccessLayer'user class to set Attributes and use UserID to constructe a identity object
public MyPrinciple(int UserID)
{
Account account=new Account();
roleList=account.getUserRole(UserID);
permissionList=account.getUserPermission(UserID);
identity=new MyIdentity(UserID);
}
public IIdentity Identity
{
get
{
return identity;
}
set
{
identity = value;
}
}
public bool IsInRole(string role)
{
return roleList.Contains( role );
}
public bool HasPermission( int permissionID )
{
return permissionList.Contains( permissionID );
}
public ArrayList Permissions
{
get
{
return permissionList;
}
}
public ArrayList Roles
{
get
{
return roleList;
}
}
}
}
MyIdentity.cs
using System;
using System.Security.Principal;
using RoleAuthenticationDataAccessLayer;
using System.Data;
namespace RolsesAuthenticationBL
{
/// <summary>
/// MyIdentity 的摘要说明。
/// </summary>
///
public class MyIdentity:IIdentity
{
private string _Name;
private int _UserID;
private string _FriendName;
private byte[] _Password;
public MyIdentity()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
//use userid for set attribute use DataAccessLayer'user class
public MyIdentity(int UserID)
{
_UserID=UserID;
Account account=new Account();
DataRow datarow=account.getUserInfo(UserID);
_Name=(string)datarow["UserName"];
_FriendName=(string)datarow["UserFriendName"];
_Password=(byte[])datarow["UserPassword"];
}
public bool IsAuthenticated
{
get
{
return true;
}
}
public string AuthenticationType
{
get
{
return "MyCustom";
}
}
public string Name
{
get
{
return _Name;
}
}
public int UserID
{
get
{
return _UserID;
}
}
public string FriendName
{
get
{
return _FriendName;
}
}
public byte[] Password
{
get
{
return _Password;
}
}
}
}
User封装验证,由于关注的是实现角色验证这个类没什么功能。
最后在SignIn.aspx中登陆后,在testpage.aspx中的Page_Load()中重新为User指定Principle,
if(Context.User.Identity.IsAuthenticated)
{
status.Text="I am Authenticationed";
if(!(Context.User is MyPrinciple))
{
status.Text=status.Text+" I am not MyPrincipleType!";
Context.User=new MyPrinciple(int.Parse(User.Identity.Name));
}
}
else
{
Response.Redirect("SignIn.aspx");
}
也可以在Globle.asax中为设置User,不要在Application_BeginRequest()中,试了一下是不行的,原因很简单,请你想一下,在验证和授权中吧。好了用一个Button来测试一下,对一个需要权限ID为2的操作进行验证,
private void Button1_Click(object sender, System.EventArgs e)
{
status.Text=User.GetType().ToString();
if(((MyPrinciple)User).HasPermission(2))
{
status.Text=status.Text+" and you have the permission";
}
else
{
status.Text="sorry you hava'not the permission";
}
}
OK结果符合了预期的效果。
图:
好了,入门学习,水平不高,希望大家指正。
浙公网安备 33010602011771号