zoukankan      html  css  js  c++  java
  • WEB开发中使用和理解 .net中的认证与授权

    WEB 中 我们项目开发的方式是。利用两个类。

    一个是

     public class UserIdentity : System.Security.Principal.IIdentity
    

    一个是

     public class UserPrincipal : System.Security.Principal.IPrincipal
    

    自己根据所需要的管理员或者用户信息类型来建立 对应的  “标识对象”和“授权信息。”

    请注意,context.user是IPrincipal(用户对象)类型接口,而identity是IIdentity(标志对象)类型的接口。
    
    

    在这里。如果你利用context.user.identity 还是   FormsAuthentication.SetAuthCookie(userName, false); 方式写进入的用户名信息

    但如果 -----你利用自己写的 UserPrincipal类的实例 赋值给 Context.user。那么你再从其他页面用Context.user得到的可以是很多信息。

    使用方式是(((UserIdentity)Page.User.Identity)  强制转换成 UserIdentity类型。这样就可以得到里面的一些属性(UserIdentity中的一些信息)和使用一些方法功能(UserPrincipal 中的一些方法功能)。

         Security.UserPrincipal newUser = Security.UserPrincipal.VaLogin(userName, password);
                       if (newUser == null)//用户如果不合法
                {
                    return false;
                }
                else//用户如果合法
                {
                    //把生成的用户对象放入Context.User,这样做将会把完整的用户信息加载到ASP.NET提供的验证体系中
                    Context.User = newUser;
    
                    //再次验证当前用户密码
    //Page:     public IPrincipal User { get; } 这样可以在页面里使用。 
                    if (((UserIdentity)User.Identity).Testword(userName, password) == 0)
                    {
                        return false;
                    }
                    else
                    {
                        Session["UserInfo"] = currentUser;//把对象信息放入session中,备用
                        FormsAuthentication.SetAuthCookie(userName, false);
                        return true;
                    }
                }
    

    在这里:我要声明一下为什么 有了 FormsAuthentication.SetAuthCookie(userName, false);
    还要用Principal。 因为FORM是用来做验证的。 只是简单的验证,并存储单个用户名信息。  而 Principal是做授权用的。我们可以利用自己写的继承Principal类的对象,既进行 验证(放在UserIdentity)用户名和密码 和一些简单的属性信息 。还可以用来对授权信息(角色)分配 (UserPrincipal)进行权限信息的控制。 

    以下是相关资料

    —————————————————————————————————————————————————————— 

     “认证”与“授权”是几乎所有系统中都会涉及的概念,通俗点讲:

      1、认证(authentication) 就是 "判断用户有没有登录?",好比windows系统,没登录就无法使用(不管你是用Administrator或Guest用户,总之要先正确登录后,才能进入系统)。

      2、授权(authorization) 就是"用户登录后的身份/角色识别",好比"管理员用户"登录windows后,能安装软件、修改windows设置等所有操作,而Guest用户登录后,只有做有限的操作(比如安装软件就被禁止了)。

       .net中与"认证"对应的是IIdentity接口,而与"授权"对应的则是IPrincipal接口,这二个接口的定义均在命名空间System.Security.Principal中: 

    using System;
    using System.Runtime.InteropServices;

    namespace System.Security.Principal
    {
    [ComVisible(
    true)]
    public interface IIdentity
    {
    string AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string Name { get; }
    }
    }
    using System;
    using System.Runtime.InteropServices;

    namespace System.Security.Principal
    {
    [ComVisible(
    true)]
    public interface IPrincipal
    {
    IIdentity Identity {
    get; }
    bool IsInRole(string role);
    }
    }
    应该注意到:IPrincipal接口中包含着一个只读的IIdentity,这也跟最开始提到的概念一致:识别身份的前提是先登录,只有登录成功后能进一步确认身份。

      用Membership/Role做过asp.net开发的朋友们,看到这二个接口的定义,应该会觉得很眼熟,想想我们在Asp.Net页面中是如何判断用户是否登录以及角色的?

    protected void Page_Load(object sender, EventArgs e)
    {
    HttpContext ctx
    = HttpContext.Current;
    if (ctx.User.Identity.IsAuthenticated && ctx.User.IsInRole("管理员"))
    {
    //管理员该做的事,就写在这里
    }
    else
    {
    //Hi,您不是管理员,别胡来!
    }
    }

      这段代码再熟悉不过了,没错!membership/role的原理就是基于这二个接口的,如果再对HttpContext.Current.User刨根问底,能发现下面的定义:

      即:HttpContext.Current.User本身就是一个IPrincipal接口的实例。有了上面的预备知识,可以直奔主题了,先来一个Console控制台程序测试一下用法:

    using System;
    using System.Security.Principal;
    using System.Threading;

    namespace ConsoleTest
    {
    class Program
    {
    static void Main(string[] args)
    {

    GenericIdentity _identity
    = new GenericIdentity("菩提树下的杨过");
    GenericPrincipal _principal
    = new GenericPrincipal(_identity, new string[] {"管理员","网站会员" });

    Thread.CurrentPrincipal
    = _principal;//并非必需,但在winform程序中有很用(后面会提到)

    string loginName = _principal.Identity.Name;
    bool isLogin = _principal.Identity.IsAuthenticated;
    bool isAdmin = _principal.IsInRole("管理员");
    bool isWebUser = _principal.IsInRole("网站会员");

    Console.WriteLine(
    "当前用户: {0}", loginName);
    Console.WriteLine(
    "是否已经登录? {0}", isLogin);
    Console.WriteLine(
    "是否管理员? {0}", isAdmin);
    Console.WriteLine(
    "是否网站会员? {0}", isWebUser);

    Console.Read();
    }
    }
    }

      输出如下:

    当前用户: 菩提树下的杨过
    是否已经登录? True
    是否管理员? True
    是否网站会员? True

      一切正常,没什么大不了,但Console默认只是一个单线程的程序,也没有丰富的GUI界面,所以...这个只不过是热身,看下接口定义的几个方法是否管用而已。

      这二个接口同样也能用在Winform程序中,下面将创建一个WinForm应用,里面有二个窗口:Form1以及Form2,可以把Form1当成登录界面,而Form2则是程序主窗口,在很多管理软件中,主窗口都要求登录以后才能访问,我们就来模拟一下:

      Form1的界面:

      Form2更简单:(就一个只读的TextBox)

      我想做的事情:在Form1上登录后,看看在Form2中,能否判断出用户已经登录,以及识别出身份。

      Form1 中的代码:

    using System;
    using System.Security.Principal;
    using System.Threading;
    using System.Windows.Forms;

    namespace WinformTest
    {
    public partial class Form1 : Form
    {
    public Form1()
    {
    InitializeComponent();
    }

    private void btnLogin_Click(object sender, EventArgs e)
    {
    if (txtUserName.Text.Trim() == "") {
    MessageBox.Show(
    "请输入用户名!");
    txtUserName.Focus();
    return;
    }

    IIdentity _identity
    = new GenericIdentity(txtUserName.Text.Trim());
    IPrincipal _principal
    = new GenericPrincipal(_identity, new string[] { "管理员" });

    Thread.CurrentPrincipal
    = _principal;//将其附加到当前线程的CurrentPrincipal

    MessageBox.Show(
    "登录成功!");
    }

    private void btnShow_Click(object sender, EventArgs e)
    {
    (
    new Form2()).ShowDialog();
    }

    private void btnLogOut_Click(object sender, EventArgs e)
    {
    Thread.CurrentPrincipal
    = null;
    MessageBox.Show(
    "已经退出!");
    }
    }
    }

      Form2中的代码:

    using System;
    using System.Security.Principal;
    using System.Threading;
    using System.Windows.Forms;

    namespace WinformTest
    {
    public partial class Form2 : Form
    {
    public Form2()
    {
    InitializeComponent();
    }

    private void Form2_Load(object sender, EventArgs e)
    {
    IPrincipal _principal
    = Thread.CurrentPrincipal;

    if (_principal.Identity.IsAuthenticated)
    {
    this.textBox1.Text = "您已经登录,当前用户:" + _principal.Identity.Name;
    this.textBox1.Text += Environment.NewLine + "当前角色:" + (_principal.IsInRole("管理员") ? "管理员" : "非管理员");
    }
    else
    {
    this.textBox1.Text = "您还没有登录";
    }
    }
    }
    }

      测试一下:如果在未登录的情况下,直接点击"Show窗体2",结果如下。

      如果输入用户名,并点击"登录"后,再点击"Show窗体2",结果如下:

      很理想!Form2中直接就能判断用户是否登录,以及当前登录用户的角色。这里有一个关键的细节:

    Thread.CurrentPrincipal = _principal;//将其附加到当前线程的CurrentPrincipal

      在Form1中,将登录后的_principal附加到当前线程的CurrentPrincipal,我们知道:每个程序不管它是不是多线程,总归是有一个默认的主线程的。所以只要把主线程的CurrentPrincipal与登录后的_principal关联起来后,其它任何窗体,都可以直接用它来做判断,如果判断通过,则可以这样或那样(包括创建多线程进行自己的处理),如果判断不通过,则可以拒绝继续操作。

      Winform的问题解决了,再来考虑一下Webform,当然,你可以直接使用从Asp.Net2.0就支持的membership/role机制,但membership/role默认只支持sqlserver数据库(通过membership provider for oracle也可以支持oracle,但总有一些数据库不被支持,比如access、mysql、sqlite、db2等),假如你不想把用户名/密码这类信息保存在sqlserver中(甚至不想保存在数据库中,比如:xml),这时候就得开动脑筋了。

      其实...就算不用membership/role,上面提到的这二个接口仍然是可以使用的,但有一个问题:winform中,IPrincipal接口的实例可以一直存储在内存中(直到程序退出),所以其它窗口就能继续访问它,以便做进一步的判断,但是在webform中,页面本身是无状态的,一旦服务器输出html到客户端浏览器后,客户端的页面就与服务器再无瓜葛了(你甚至可以离线浏览,前提是不刷新),那么最后的认证信息保存在什么地方呢?

    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

  • 相关阅读:
    CentOS7 命令笔记
    MarkDown学习
    系统管理员资源大全
    解决回车键导致的页面无意义刷新
    Tomcat远程调试
    gson 自定义对象转换格式
    maven私服搭建
    大明最不该被遗忘的英烈——李定国
    HashMap实现原理分析(转)
    自定义评分器Similarity,提高搜索体验(转)
  • 原文地址:https://www.cnblogs.com/mahaisong/p/2064180.html
Copyright © 2011-2022 走看看