zoukankan      html  css  js  c++  java
  • .NET 实现自定义ContextUser的Identity和Principal实现自定义用户信息,权限验证。

    .NET 实现自定义ContextUser的Identity和Principal 

    在传统的.NET中,我们可以通过

    1. User.Identity.Name;//获取用户名   
    2.   
    3. User.Identity.IsAuthenticated;//判断用户是否己验证   
    4.   
    5. User.IsInRole("Admin");//判断用户是否含有指定角色  
            User.Identity.Name;//获取用户名
    
            User.Identity.IsAuthenticated;//判断用户是否己验证
    
            User.IsInRole("Admin");//判断用户是否含有指定角色
    
    


     

    但这样的机制,在实际开发中,难以满足开发需要.仅仅通过User.Identity.Name;获取用户名,和User.Identity.IsAuthenticated;判断用户是否验证,是难以满足需要。如何获取用户更多信息,或者进行更详细的权限判断。

    我们可以通过自定义Identity和Principal进行实现!

    1. /// <summary>   
    2.   
    3. /// 自定义当前用户标识对象   
    4.   
    5. /// </summary>   
    6.   
    7. public class MyIdentity:IIdentity  
    8.   
    9. {  
    10.  
    11.  
    12.  
    13.     #region 用户属性(可自定义更多信息)   
    14.   
    15.     private string _userName;//用户账号   
    16.   
    17.     private string _departmnet;//用户所在部门   
    18.   
    19.     private string _phone;//用户联系电话  
    20.  
    21.     #endregion   
    22.   
    23.   
    24.   
    25.     /// <summary>   
    26.   
    27.     /// 用户账号   
    28.   
    29.     /// </summary>   
    30.   
    31.     public string UserName  
    32.   
    33.     {  
    34.   
    35.         get { return _userName; }  
    36.   
    37.     }  
    38.   
    39.     /// <summary>   
    40.   
    41.     /// 用户所在部门   
    42.   
    43.     /// </summary>   
    44.   
    45.     public string Departmnet  
    46.   
    47.     {  
    48.   
    49.         get { return _departmnet; }  
    50.   
    51.     }  
    52.   
    53.     /// <summary>   
    54.   
    55.     /// 用户电话   
    56.   
    57.     /// </summary>   
    58.   
    59.     public string Phone  
    60.   
    61.     {  
    62.   
    63.         get { return _phone; }  
    64.   
    65.     }  
    66.   
    67.     /// <summary>   
    68.   
    69.     /// 构造函数,根据用户名   
    70.   
    71.     /// </summary>   
    72.   
    73.     /// <param name="UserName"></param>   
    74.   
    75.     public MyIdentity(string UserName)  
    76.   
    77.     {  
    78.   
    79.         //根据UserName查询数据库获得以下数据   
    80.   
    81.         this._userName = "abc";  
    82.   
    83.         this._departmnet = "行政部";  
    84.   
    85.         this._phone = "123456";  
    86.   
    87.     }  
    88.   
    89.     /// <summary>   
    90.   
    91.     /// 构造函数,根据用户ID   
    92.   
    93.     /// </summary>   
    94.   
    95.     /// <param name="UserID"></param>   
    96.   
    97.     public MyIdentity(int UserID)  
    98.   
    99.     {  
    100.   
    101.         //根据UserName查询数据库获得以下数据   
    102.   
    103.         this._userName = "abc";  
    104.   
    105.         this._departmnet = "行政部";  
    106.   
    107.         this._phone = "123456";  
    108.   
    109.     }  
    110.  
    111.     #region 基本属性   
    112.   
    113.     /// <summary>   
    114.   
    115.     /// 返回验证方式   
    116.   
    117.     /// </summary>   
    118.   
    119.     public string AuthenticationType  
    120.   
    121.     {  
    122.   
    123.         get { return "Form"; }  
    124.   
    125.     }  
    126.   
    127.     /// <summary>   
    128.   
    129.     /// 是否验证   
    130.   
    131.     /// </summary>   
    132.   
    133.     public bool IsAuthenticated  
    134.   
    135.     {  
    136.   
    137.         get { return true; }  
    138.   
    139.     }  
    140.   
    141.     /// <summary>   
    142.   
    143.     /// 返回用户   
    144.   
    145.     /// </summary>   
    146.   
    147.     public string Name  
    148.   
    149.     {  
    150.   
    151.         get { return _userName; }  
    152.   
    153.     }  
    154.  
    155.     #endregion   
    156.   
    157. }  
        /// <summary>
    
        /// 自定义当前用户标识对象
    
        /// </summary>
    
        public class MyIdentity:IIdentity
    
        {
    
     
    
            #region 用户属性(可自定义更多信息)
    
            private string _userName;//用户账号
    
            private string _departmnet;//用户所在部门
    
            private string _phone;//用户联系电话
    
            #endregion
    
     
    
            /// <summary>
    
            /// 用户账号
    
            /// </summary>
    
            public string UserName
    
            {
    
                get { return _userName; }
    
            }
    
            /// <summary>
    
            /// 用户所在部门
    
            /// </summary>
    
            public string Departmnet
    
            {
    
                get { return _departmnet; }
    
            }
    
            /// <summary>
    
            /// 用户电话
    
            /// </summary>
    
            public string Phone
    
            {
    
                get { return _phone; }
    
            }
    
            /// <summary>
    
            /// 构造函数,根据用户名
    
            /// </summary>
    
            /// <param name="UserName"></param>
    
            public MyIdentity(string UserName)
    
            {
    
                //根据UserName查询数据库获得以下数据
    
                this._userName = "abc";
    
                this._departmnet = "行政部";
    
                this._phone = "123456";
    
            }
    
            /// <summary>
    
            /// 构造函数,根据用户ID
    
            /// </summary>
    
            /// <param name="UserID"></param>
    
            public MyIdentity(int UserID)
    
            {
    
                //根据UserName查询数据库获得以下数据
    
                this._userName = "abc";
    
                this._departmnet = "行政部";
    
                this._phone = "123456";
    
            }
    
            #region 基本属性
    
            /// <summary>
    
            /// 返回验证方式
    
            /// </summary>
    
            public string AuthenticationType
    
            {
    
                get { return "Form"; }
    
            }
    
            /// <summary>
    
            /// 是否验证
    
            /// </summary>
    
            public bool IsAuthenticated
    
            {
    
                get { return true; }
    
            }
    
            /// <summary>
    
            /// 返回用户
    
            /// </summary>
    
            public string Name
    
            {
    
                get { return _userName; }
    
            }
    
            #endregion
    
        }
    
    


     

    1. /// <summary>   
    2.   
    3. /// 当前用户安全上下文信息   
    4.   
    5. /// </summary>   
    6.   
    7. public class MyPrincipal:IPrincipal  
    8.   
    9. {  
    10.  
    11.     #region 属性   
    12.   
    13.     private IIdentity _identity;//用户标识   
    14.   
    15.     private ArrayList _permissionList;//权限列表  
    16.  
    17.     #endregion   
    18.   
    19.   
    20.   
    21.     /// <summary>   
    22.   
    23.     /// 返回用户权限列表   
    24.   
    25.     /// </summary>   
    26.   
    27.     public ArrayList PermissionList  
    28.   
    29.     {  
    30.   
    31.         get { return _permissionList; }  
    32.   
    33.     }  
    34.   
    35.   
    36.   
    37.     /// <summary>   
    38.   
    39.     /// 获取当前用户标识   
    40.   
    41.     /// </summary>   
    42.   
    43.     public IIdentity Identity  
    44.   
    45.     {  
    46.   
    47.         get { return _identity; }  
    48.   
    49.     }  
    50.   
    51.     /// <summary>   
    52.   
    53.     /// 当前用户是否指定角色(采用权限值方式,此处返回false)   
    54.   
    55.     /// </summary>   
    56.   
    57.     /// <param name="role"></param>   
    58.   
    59.     /// <returns></returns>   
    60.   
    61.     public bool IsInRole(string role)  
    62.   
    63.     {  
    64.   
    65.         return false;//返回false   
    66.   
    67.     }  
    68.   
    69.     /// <summary>   
    70.   
    71.     /// 构造函数,用户名构造   
    72.   
    73.     /// </summary>   
    74.   
    75.     /// <param name="UserName"></param>   
    76.   
    77.     public MyPrincipal(string UserName)  
    78.   
    79.     {  
    80.   
    81.         _identity = new MyIdentity(UserName);  
    82.   
    83.         //以下权限根据UserName获取数据库用户拥有的权限值,此次省略   
    84.   
    85.         _permissionList = new ArrayList();  
    86.   
    87.         _permissionList.Add(1);  
    88.   
    89.         _permissionList.Add(2);  
    90.   
    91.         _permissionList.Add(3);  
    92.   
    93.         _permissionList.Add(4);  
    94.   
    95.         _permissionList.Add(5);  
    96.   
    97.     }  
    98.   
    99.     /// <summary>   
    100.   
    101.     /// 构造函数,用户ID构造   
    102.   
    103.     /// </summary>   
    104.   
    105.     /// <param name="UserID"></param>   
    106.   
    107.     public MyPrincipal(int UserID)  
    108.   
    109.     {  
    110.   
    111.         _identity = new MyIdentity(UserID);  
    112.   
    113.         //以下权限根据UserName获取数据库用户拥有的权限值,此次省略   
    114.   
    115.         _permissionList = new ArrayList();  
    116.   
    117.         _permissionList.Add(1);  
    118.   
    119.         _permissionList.Add(2);  
    120.   
    121.         _permissionList.Add(3);  
    122.   
    123.         _permissionList.Add(4);  
    124.   
    125.         _permissionList.Add(5);  
    126.   
    127.     }  
    128.   
    129.     /// <summary>   
    130.   
    131.     /// 判断用户是否拥有某权限   
    132.   
    133.     /// </summary>   
    134.   
    135.     /// <param name="permissionid"></param>   
    136.   
    137.     /// <returns></returns>   
    138.   
    139.     public bool IsPermissionID(int permissionid)  
    140.   
    141.     {  
    142.   
    143.         return _permissionList.Contains(permissionid);  
    144.   
    145.     }  
    146.   
    147. }  
        /// <summary>
    
        /// 当前用户安全上下文信息
    
        /// </summary>
    
        public class MyPrincipal:IPrincipal
    
        {
    
            #region 属性
    
            private IIdentity _identity;//用户标识
    
            private ArrayList _permissionList;//权限列表
    
            #endregion
    
     
    
            /// <summary>
    
            /// 返回用户权限列表
    
            /// </summary>
    
            public ArrayList PermissionList
    
            {
    
                get { return _permissionList; }
    
            }
    
     
    
            /// <summary>
    
            /// 获取当前用户标识
    
            /// </summary>
    
            public IIdentity Identity
    
            {
    
                get { return _identity; }
    
            }
    
            /// <summary>
    
            /// 当前用户是否指定角色(采用权限值方式,此处返回false)
    
            /// </summary>
    
            /// <param name="role"></param>
    
            /// <returns></returns>
    
            public bool IsInRole(string role)
    
            {
    
                return false;//返回false
    
            }
    
            /// <summary>
    
            /// 构造函数,用户名构造
    
            /// </summary>
    
            /// <param name="UserName"></param>
    
            public MyPrincipal(string UserName)
    
            {
    
                _identity = new MyIdentity(UserName);
    
                //以下权限根据UserName获取数据库用户拥有的权限值,此次省略
    
                _permissionList = new ArrayList();
    
                _permissionList.Add(1);
    
                _permissionList.Add(2);
    
                _permissionList.Add(3);
    
                _permissionList.Add(4);
    
                _permissionList.Add(5);
    
            }
    
            /// <summary>
    
            /// 构造函数,用户ID构造
    
            /// </summary>
    
            /// <param name="UserID"></param>
    
            public MyPrincipal(int UserID)
    
            {
    
                _identity = new MyIdentity(UserID);
    
                //以下权限根据UserName获取数据库用户拥有的权限值,此次省略
    
                _permissionList = new ArrayList();
    
                _permissionList.Add(1);
    
                _permissionList.Add(2);
    
                _permissionList.Add(3);
    
                _permissionList.Add(4);
    
                _permissionList.Add(5);
    
            }
    
            /// <summary>
    
            /// 判断用户是否拥有某权限
    
            /// </summary>
    
            /// <param name="permissionid"></param>
    
            /// <returns></returns>
    
            public bool IsPermissionID(int permissionid)
    
            {
    
                return _permissionList.Contains(permissionid);
    
            }
    
        }
    
    


     

    好,上面我们己实现了自定义,Identity和Principal。

    我们可以在页面这样使用Identity。

    1. //页面中输出自定义用户信息   
    2.   
    3. <%=(User.Identity as ContextUser.MyIdentity).Name %>//用户账号   
    4.   
    5. <%=(User.Identity as ContextUser.MyIdentity).Phone %>//用户电话   
    6.   
    7. <%=(User.Identity as ContextUser.MyIdentity).Departmnet %>//用户所在部门  
    //页面中输出自定义用户信息
    
    <%=(User.Identity as ContextUser.MyIdentity).Name %>//用户账号
    
    <%=(User.Identity as ContextUser.MyIdentity).Phone %>//用户电话
    
    <%=(User.Identity as ContextUser.MyIdentity).Departmnet %>//用户所在部门
    
    


     

    自定义显示用户信息后,我们接着利用Principal进行权限验证和控制

    在Asp.net Web模式下,使用方式:

    首先,我们先做一个权限验证基类!

    1. /// <summary>   
    2.   
    3. ///权限验证基类   
    4.   
    5. /// </summary>   
    6.   
    7. public class BasePaper:System.Web.UI.Page  
    8.   
    9. {  
    10.   
    11.     public BasePaper()  
    12.   
    13.        {  
    14.   
    15.               //   
    16.   
    17.               //TODO: 在此处添加构造函数逻辑   
    18.   
    19.               //   
    20.   
    21.        }  
    22.   
    23.     protected override void OnInit(EventArgs e)  
    24.   
    25.     {  
    26.   
    27.         BasePage_Load();  
    28.   
    29.     }  
    30.   
    31.     /// <summary>   
    32.   
    33.     /// 设置权限,默认值为0   
    34.   
    35.     /// </summary>   
    36.   
    37.     public virtual int PermissionID  
    38.   
    39.     {  
    40.   
    41.         get { return 0; }  
    42.   
    43.     }  
    44.   
    45.     /// <summary>   
    46.   
    47.     /// 验证方法   
    48.   
    49.     /// </summary>   
    50.   
    51.     /// <param name="sender"></param>   
    52.   
    53.     /// <param name="e"></param>   
    54.   
    55.     private void BasePage_Load()  
    56.   
    57.     {  
    58.   
    59.         //权限检查  
    60.  
    61.         #region 权限检查   
    62.   
    63.         bool Permission = true;//初始值为没有权限   
    64.   
    65.    
    66.   
    67.                 //这一步很重要,要代替.NET的自身的User.   
    68.   
    69.                 ContextUser.MyPrincipal MyPrincipal = new ContextUser.MyPrincipal(HttpContext.Current.User.Identity.Name);  
    70.   
    71.                 HttpContext.Current.User = MyPrincipal;  
    72.   
    73.         if ((User as account.ContextUser.MyPrincipal).PermissionList.Contains(PermissionID))  
    74.   
    75.         {  
    76.   
    77.             Permission = false;//验证通过   
    78.   
    79.         }  
    80.   
    81.         if (Permission)//权限验证不通过   
    82.   
    83.         {  
    84.   
    85.             Response.Clear();  
    86.   
    87.             Response.Write("<script language=\"javascript\">alert(\"对不起,你没有权限进入\");history.go(-1);</script>");  
    88.   
    89.             Response.End();  
    90.   
    91.         }  
    92.  
    93.         #endregion   
    94.   
    95.     }  
    96.   
    97. }  
    /// <summary>
    
    ///权限验证基类
    
    /// </summary>
    
    public class BasePaper:System.Web.UI.Page
    
    {
    
        public BasePaper()
    
           {
    
                  //
    
                  //TODO: 在此处添加构造函数逻辑
    
                  //
    
           }
    
        protected override void OnInit(EventArgs e)
    
        {
    
            BasePage_Load();
    
        }
    
        /// <summary>
    
        /// 设置权限,默认值为0
    
        /// </summary>
    
        public virtual int PermissionID
    
        {
    
            get { return 0; }
    
        }
    
        /// <summary>
    
        /// 验证方法
    
        /// </summary>
    
        /// <param name="sender"></param>
    
        /// <param name="e"></param>
    
        private void BasePage_Load()
    
        {
    
            //权限检查
    
            #region 权限检查
    
            bool Permission = true;//初始值为没有权限
    
     
    
                    //这一步很重要,要代替.NET的自身的User.
    
                    ContextUser.MyPrincipal MyPrincipal = new ContextUser.MyPrincipal(HttpContext.Current.User.Identity.Name);
    
                    HttpContext.Current.User = MyPrincipal;
    
            if ((User as account.ContextUser.MyPrincipal).PermissionList.Contains(PermissionID))
    
            {
    
                Permission = false;//验证通过
    
            }
    
            if (Permission)//权限验证不通过
    
            {
    
                Response.Clear();
    
                Response.Write("<script language=\"javascript\">alert(\"对不起,你没有权限进入\");history.go(-1);</script>");
    
                Response.End();
    
            }
    
            #endregion
    
        }
    
    }
    
    


     

    OK,到了验证页的时候了。

    1. public partial class ascx_Add :BasePage  
    2.   
    3. {  
    4.   
    5.     public override int PermissionID  
    6.   
    7.     {  
    8.   
    9.         get  
    10.   
    11.         {  
    12.   
    13.             return 13;//返回要验证权限值   
    14.   
    15.         }  
    16.   
    17.     }  
    18.   
    19.     protected void Page_Load(object sender, EventArgs e)  
    20.   
    21.     {  
    22.   
    23.         //   
    24.   
    25.     }  
    26.   
    27. }  
    public partial class ascx_Add :BasePage
    
    {
    
        public override int PermissionID
    
        {
    
            get
    
            {
    
                return 13;//返回要验证权限值
    
            }
    
        }
    
        protected void Page_Load(object sender, EventArgs e)
    
        {
    
            //
    
        }
    
    }
    
    

    事实上,在Asp.net MVC模式,更容易对权限进行控制,可以进行更多的细化,对每个动作进行控制。

    MVC模式下:

    首先,先实现一个权限验证基类:

    1. /// <summary>   
    2.   
    3. /// 权限验证基类   
    4.   
    5. /// 2011.7.3   
    6.   
    7. /// </summary>   
    8.   
    9. public class BasePage : AuthorizeAttribute  
    10.   
    11. {  
    12.   
    13.     /// <summary>   
    14.   
    15.     /// 权限值   
    16.   
    17.     /// </summary>   
    18.   
    19.     private int _permissionID = 0;  
    20.   
    21.     /// <summary   
    22.   
    23.     /// 权限值   
    24.   
    25.     /// </summary>   
    26.   
    27.     public int PermissionID  
    28.   
    29.     {  
    30.   
    31.         get { return _permissionID; }  
    32.   
    33.         set { _permissionID = value; }  
    34.   
    35.     }  
    36.   
    37.     /// <summary>   
    38.   
    39.     /// 在过程请求授权时调用。    
    40.   
    41.     /// </summary>   
    42.   
    43.     /// <param name="filterContext">对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。</param>   
    44.   
    45.     public override void OnAuthorization(AuthorizationContext filterContext)  
    46.   
    47.     {  
    48.   
    49.         if (HttpContext.Current.User.Identity.IsAuthenticated)  
    50.   
    51.         {  
    52.   
    53.             //这一步很重要,要代替.NET的自身的User.   
    54.   
    55.             ContextUser.MyPrincipal MyPrincipal = new ContextUser.MyPrincipal(HttpContext.Current.User.Identity.Name);  
    56.   
    57.             HttpContext.Current.User = MyPrincipal;  
    58.   
    59.   
    60.   
    61.             if ((!MyPrincipal.ISPermissionID(_permissionID)) && (_permissionID != 0))  
    62.   
    63.             {  
    64.   
    65.                 HttpContext.Current.Response.Clear();  
    66.   
    67.                 HttpContext.Current.Response.Write("<script defer>window.alert('无权操作!');history.back();</script>");  
    68.   
    69.                 HttpContext.Current.Response.End();  
    70.   
    71.                 filterContext.Result = new EmptyResult();  
    72.   
    73.             }  
    74.   
    75.         }  
    76.   
    77.         else  
    78.   
    79.         {  
    80.   
    81.             FormsAuthentication.SignOut();  
    82.   
    83.             HttpContext.Current.Response.Clear();  
    84.   
    85.             HttpContext.Current.Response.Write("<script defer>window.alert('无权操作!或当前登录用户已过期!\\n请重新登录或与管理员联系!');</script>");  
    86.   
    87.             HttpContext.Current.Response.End();  
    88.   
    89.             filterContext.Result = new EmptyResult();  
    90.   
    91.         }  
    92.   
    93.     }  
    94.   
    95.   
    96.   
    97. }  
        /// <summary>
    
        /// 权限验证基类
    
        /// 2011.7.3
    
        /// </summary>
    
        public class BasePage : AuthorizeAttribute
    
        {
    
            /// <summary>
    
            /// 权限值
    
            /// </summary>
    
            private int _permissionID = 0;
    
            /// <summary
    
            /// 权限值
    
            /// </summary>
    
            public int PermissionID
    
            {
    
                get { return _permissionID; }
    
                set { _permissionID = value; }
    
            }
    
            /// <summary>
    
            /// 在过程请求授权时调用。 
    
            /// </summary>
    
            /// <param name="filterContext">对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。</param>
    
            public override void OnAuthorization(AuthorizationContext filterContext)
    
            {
    
                if (HttpContext.Current.User.Identity.IsAuthenticated)
    
                {
    
                    //这一步很重要,要代替.NET的自身的User.
    
                    ContextUser.MyPrincipal MyPrincipal = new ContextUser.MyPrincipal(HttpContext.Current.User.Identity.Name);
    
                    HttpContext.Current.User = MyPrincipal;
    
     
    
                    if ((!MyPrincipal.ISPermissionID(_permissionID)) && (_permissionID != 0))
    
                    {
    
                        HttpContext.Current.Response.Clear();
    
                        HttpContext.Current.Response.Write("<script defer>window.alert('无权操作!');history.back();</script>");
    
                        HttpContext.Current.Response.End();
    
                        filterContext.Result = new EmptyResult();
    
                    }
    
                }
    
                else
    
                {
    
                    FormsAuthentication.SignOut();
    
                    HttpContext.Current.Response.Clear();
    
                    HttpContext.Current.Response.Write("<script defer>window.alert('无权操作!或当前登录用户已过期!\\n请重新登录或与管理员联系!');</script>");
    
                    HttpContext.Current.Response.End();
    
                    filterContext.Result = new EmptyResult();
    
                }
    
            }
    
     
    
        }
    
    


     

    回到控制器,进行权限验证

    1. [BasePage(PermissionID = 13)]//返回要验证权限值   
    2.   
    3. public ActionResult Index()  
    4.   
    5. {  
    6.   
    7.    //   
    8.   
    9. }  
            [BasePage(PermissionID = 13)]//返回要验证权限值
    
            public ActionResult Index()
    
            {
    
               //
    
            }
    
    


     

    无论对Asp.net Form或者Aap.net MVC,都在一个按钮级的权限控制,

    那对于,按钮级的权限如何进行控制昵?

    看下面代码

    1. //控制删除按扭的显示   
    2.   
    3. <% if((User as account.ContextUser.MyPrincipal).PermissionList.Contains(13) {%>  
    4.   
    5. <input type="submit" name="button" id="button" value="删除" />  
    6.   
    7. <%} %>  
        //控制删除按扭的显示
    
        <% if((User as account.ContextUser.MyPrincipal).PermissionList.Contains(13) {%>
    
        <input type="submit" name="button" id="button" value="删除" />
    
        <%} %>
    
    


     

    至此,如何实现自定义Identity和Principal,进行整合更多用户信息,和权限验证。己经介绍完了。

  • 相关阅读:
    Serialize and Deserialize Binary Tree
    sliding window substring problem汇总贴
    10. Regular Expression Matching
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第七章 链接
    程序员如何写一份合格的简历?(附简历模版)
    9个提高代码运行效率的小技巧你知道几个?
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第六章 存储器层次结构
    24张图7000字详解计算机中的高速缓存
    《深入理解计算机系统》(CSAPP)实验四 —— Attack Lab
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第五章 优化程序性能
  • 原文地址:https://www.cnblogs.com/aweifly/p/2709148.html
Copyright © 2011-2022 走看看