zoukankan      html  css  js  c++  java
  • ADO.NET Data Service:如何做身份验证

    ADO.NET Data Service是基于WCF的一套REST风格的服务,但是它在很多方面又与WCF很不一样,典型的情况就是在身份验证方面。这篇文章专门来说一说如何为其实现身份验证。

    1. 采用Windows验证方式。

    这种方式总是最简单也是最安全的。基本上我们也无需做太多事情。

    web.config中配置

    <authentication mode="Windows"/>
        <authorization>
          <allow users="Chenxizhang-pc\chenxizhang"/>
          <deny users="*"/>
    </authorization>

    Data Service里面,我们要通过所谓的QueryInterceptor进行拦截

            [QueryInterceptor("Customers")]
            public Expression<Func<Customers, bool>> OnQueryCustomers()
            {
                if (!HttpContext.Current.User.Identity.IsAuthenticated)
                    throw new AuthenticationException();
                else
                    return (c) => true;
            }

    这样,我们就实现了目的:该服务(或者说其他的网站资源),只允许Chenxizhang-pc\chenxizhang这个账号能访问到。

    接下来,客户端中应该怎么做呢?

                localhost.NorthwindEntities context = new localhost.NorthwindEntities(
                    new Uri("http://localhost:2549/NorthwindService.svc/"));
    
                context.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                ////查询
                var query = from c in context.Customers
                            where c.City.Equals("London")
                            select c;
    
    
                Console.WriteLine(query.ToString());
                foreach (var item in query)
                {
                    Console.WriteLine(item.CompanyName);
                }
    现在我的身份是合法的,所以能看到结果
    image 
    但是如果我把下面这一句去除掉
    <allow users="Chenxizhang-pc\chenxizhang"/>

    就会发生一个错误

    image

    很好,我们这样就实现了身份验证了。
    等一下,这样是否就真的万事大吉了呢?大家要知道,不是任何场合都有机会使用Windows验证的,例如在internet上,可能就无法使用Windows验证方式。
    那么,是不是可以使用传统的Forms验证呢?如果在一个网站内部,那么看起来确实可以:先让用户去一个页面(Login.aspx)进行登录,此时它的凭据会保存起来,然后再访问服务的话就拥有了身份。
    但是,问题是,如果仅仅在网站内部使用,那么有什么必要用Data Service呢?为什么不直接用EDM去存取数据库呢?
     
    好吧,那么,如果我们既希望在外部能访问到这个Data Service,又不想用Windows 验证,并且我们也无法使用Forms验证,那么该怎么办呢?答案是自定义验证。
    首先,我们编写一个HttpModule
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Security.Principal;
    
    namespace DataServiceAuthenticationModule
    {
        public class AuthenticationModule : IHttpModule
        {
            const string accessDeniedStatus = "拒绝访问";
            const string accessDeniedHtml = "<html><body>401 您的请求被拒绝,因为没有通过身份验证</body></html>";
            const string realmFormatString = "Basic realm=\"{0}\"";
            const string authServerHeader = "WWW-Authenticate";
            const string authClientHeader = "Authorization";
            const string basicAuth = "Basic";
    
            #region IHttpModule 成员
    
            public void Dispose()
            {
    
            }
    
            public void Init(HttpApplication context)
            {
                context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
            }
    
            void context_AuthenticateRequest(object sender, EventArgs e)
            {
                HttpApplication context = (HttpApplication)sender;
                if (context.Request.Headers["Authorization"] == null)
                {
    
                    context.Response.StatusCode = 401;
                    context.Response.StatusDescription = accessDeniedStatus;
                    context.Response.Write(accessDeniedHtml);
                    // TODO: not sure this is quite right wrt realm.
    
                    context.Response.AddHeader(authServerHeader,string.Format(realmFormatString,context.Request.Url.GetLeftPart(UriPartial.Authority)));
    
    
    
                }
    
                else
                {
    
                    string credential = ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(GetBase64CredentialsFromHeader()));
    
                    string[] usernameandpassword = credential.Split(':');
                    context.Context.User= new MyPrinciple(
                        new MyIdentity(usernameandpassword[0], Authenticate(usernameandpassword[0], usernameandpassword[1])));
    
                }
    
            }
    
            bool Authenticate(string username, string password)
            {
                //your code logic here to authenticate user
    
                if (username !="chenxizhang" || password!="password") return false;
                else
                    return true;
    
            }
    
            string GetBase64CredentialsFromHeader()
            {
    
                string credsHeader =HttpContext.Current.Request.Headers[authClientHeader];
    
                string creds = null;
    
    
    
                int credsPosition =
    
                  credsHeader.IndexOf(basicAuth, StringComparison.OrdinalIgnoreCase);
    
    
    
                if (credsPosition != -1)
                {
    
                    credsPosition += basicAuth.Length + 1;
    
    
    
                    creds = credsHeader.Substring(credsPosition,
    
                      credsHeader.Length - credsPosition);
    
                }
    
                return (creds);
    
            }
    
    
    
            #endregion
        }
    
        public class MyPrinciple : IPrincipal
        {
    
            private IIdentity _id;
    
            public MyPrinciple(IIdentity id)
            {
    
                _id = id;
    
            }
    
            public IIdentity Identity
            {
    
                get { return _id; }
    
            }
    
    
    
            public bool IsInRole(string role)
            {
    
                throw new NotImplementedException();
    
            }
    
    
    
        }
    
    
    
        public class MyIdentity : IIdentity
        {
    
            private bool _isAuthenticated = false;
    
            private string _name;
    
            public MyIdentity(string name, bool isAuthenticated)
            {
    
                _isAuthenticated = isAuthenticated;
    
                _name = name;
    
            }
    
            public string AuthenticationType
            {
    
                get { throw new NotImplementedException(); }
    
            }
    
    
    
            public bool IsAuthenticated
            {
    
                get { return _isAuthenticated; }
    
            }
    
            public string Name
            {
    
                get { return _name; }
    
            }
    
    
    
        }
    
    }
    

    然后,我们将web.config中的身份验证模式改为不验证(也就是说由我们自定义验证)

            <authentication mode="None"/>
    

    然后,我们将上面这个模块注册到配置文件中

          <add name="DataServiceAuthentication" type="DataServiceAuthenticationModule.AuthenticationModule,DataServiceAuthenticationModule"/>

    配置好之后,我们再次运行一下客户端,收到了如下的错误。这一点都不奇怪,因为我们并没有传递身份过来。

    image

    那么客户端应该如何传递身份呢

                context.Credentials = new System.Net.NetworkCredential("chenxizhang", "password");
    

    这样的话,我们就能如愿看到结果了

    image

    写到这里,我想很多朋友就看明白了,我们做了一个自定义的HttpModule,接管了请求的身份验证过程。那么现在的做法是直接比较用户名和密码,是不是很不合理呢?
    当然,正式的环境下我们不能这么做,但是你既然拿到了username,和password,其实你要怎么验证都不重要了。
     
     
  • 相关阅读:
    PHP——下载图片到本地代码
    PHP接收GET中文参数乱码的原因及解决方案
    防止表单按钮多次提交
    网站页面自动跳转
    php--防止DDos攻击代码
    数据库日期查询存在的问题
    html局部页面打印
    php中::的使用
    php基础:define()定义常数函数
    百度ueditor 拖文件或world 里面复制粘贴图片到编辑中 上传到第三方问题
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/1675307.html
Copyright © 2011-2022 走看看