zoukankan      html  css  js  c++  java
  • ASP.NET AJAX(10)__Authentication Service

    在通常情况下,如果使用AJAX方式调用WebService,则可能被恶意用户利用,造成性能以及安全性的问题,所以我们需要使用一些验证方式来保护WebService,最常见方式就是Forms Authentication,这也是一种用法很简单的方式

    一个使用FormsAuthentication保护WebService调用的示例

    首先创建一个名为ProtectedService的WebService,代码如下

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Security;
    using System.Security.Authentication;
    
    /// <summary>
    ///ProtectedService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class ProtectedService : System.Web.Services.WebService
    {
        [WebMethod]
        public int GetRandom()
        {
           
            return new Random(DateTime.Now.Millisecond).Next();
        }
    }
    

    这个WebService很简单啦,就是简单的返回一个随机数,

    这样,这个WebService,是可以随意的被访问的,我们对这个WebService作如下修改

    public int GetRandom()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)//验证当前用户是否已经登陆
            {
                throw new AuthenticationException("Error:please login first!");//若没有登陆,抛出一个异常
            }
            return new Random(DateTime.Now.Millisecond).Next();
        }

    然后才创建aspx页面

    前台代码:

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="FormsAuth.aspx.cs" Inherits="Demo09_FormsAuth" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <script language="javascript" type="text/javascript">
            function getRandom() {
                ProtectedService.GetRandom(callback, failedCallback);
            }
    
            function callback(result) {
                alert(result);
            }
    
            function failedCallback(error) {
                alert(error.get_message());
            }
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo09/ProtectedService.asmx" />
                </Services>
            </asp:ScriptManager>
            
            <input type="button" value="Get Random" onclick="getRandom()" />
            <hr />
            <asp:Button ID="btnLogin" runat="server" Text="Login" 
                onclick="btnLogin_Click" />
            <asp:Button ID="btnLogout" runat="server" Text="Logout" 
                onclick="btnLogout_Click" />
        </form>
    </body>
    </html>
    

    后台代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.Security;
    
    public partial class Demo09_FormsAuth : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
    
        }
    
        protected void btnLogin_Click(object sender, EventArgs e)
        {
            FormsAuthentication.SetAuthCookie("xiaoyaojian", false);//使用FormsAuthentication,登陆Username为xiaoyaojian的用户,false表示不使用持久化的Cookie
        }
    
        protected void btnLogout_Click(object sender, EventArgs e)
        {
            FormsAuthentication.SignOut();//注销用户
        }
    }
    

    这样,当我们直接点击Get Random按钮,则会出现一个Please login first,的错误提示,点击登陆后,再点击Get Random,正常出现一个随机数,再点击Logout,再去点击Get Random,则又会出现Please login first

    我们使用了FormsAuthectication,只允许登陆用户正常调用我们创建的WebService,在一定程度上保护了WebService

    Authentication Service

    它提供了一种使用AJAX的方式进行身份验证的功能,他是基于ASP.NET的Membership的功能,可以使用VS理工的ASP.NET 2.0应用程序的配置工具来配置

    使用Authentication Service

    出于安全性的考虑,ASP.NET AJAX 在默认情况下不会开发Authentication Service功能

    <authenticationService enabled="true|false" requireSSL="true|false" />

    这里的第二个属性,是指定是否使用SSL连接,这是一个安全的连接方式,常在一些高安全性的应用中使用

    身份验证的功能

    //登陆

    Sys.Service.AuthenticationService.login(

    userName,//用户名

    password,//密码

    isPersistent,//是否生成持久化Cookie

    customInfo,//预留字段

    redirectUrl,//登陆成功后跳转目标

    loginCompletedCallback,//身份验证完成回调函数(是完成,而不是成功)

    failedCallback,//身份验证出错回调函数(出错,而不是没有通过验证,比如超时)

    userContext//用户任意指定的上下文对象

    );

    //完成回调函数的签名

    function loginCompletedCallback(

    validCredentials,//身份验证是否成功,所以要看验证是否成功,是在这里看,而不是看是不是调用了failedCallback

    userContext,//以后不写啦,浪费键盘

    methodName,//Sys.Service.AuthenticationService.login

    ){…}

    //出错回调函数签名

    function failedCallback(

    error,//错误对象

    userContext,

    methodName

    ){…}

    //注销

    Sys.Services.AuthenticationService.logout(

    redirectUrl,//注销后跳转页面

    logoutCompletedCallback,//注销成功的回调函数

    failedCallback,//注销失败回调函数

    userContext

    );

    //注销完成回调函数的签名

    function loginCompletedCallback(

    result,//预留参数

    userContext,//

    methodName,//Sys.Service.AuthenticationService.logout

    ){…}

    //注销出错回调函数签名

    function failedCallback(

    error,//错误对象

    userContext,

    methodName

    ){…}

    一个使用Authentication Service的示例

    首先,我们需要运行ASP.NET 配置来给应用添加一个用户

    在VS里打开我们创建的网站,然后点击“网站”——“asp.net配置”,在弹出的网页中选择"安全"选项卡,然后点击“创建用户”,输入一些必要信息,点确定就可以了(这里我使用:用户名“xiaoyaojian”,密码“123123.”)

    然后创建一个ASPX页面

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="AuthService.aspx.cs" Inherits="Demo09_AuthService" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title></title>
        <script language="javascript" type="text/javascript">
            function getRandom() {
                ProtectedService.GetRandom(callback, failedCallback);
            }
    
            function callback(result) {
                alert(result);
            }
    
            function failedCallback(error) {
                alert(error.get_message());
            }
    
            function login() {
                Sys.Services.AuthenticationService.login(
                    document.getElementById("txtName").value,
                    document.getElementById("txtPassword").value,
                    false,
                    null,
                    null,
                    loginCompleted,
                    failedCallback,
                    null);
            }
    
            function loginCompleted(validCridentials, userContext, methodName) {
                alert(validCridentials ? "Congratulations!" : "Failed to login to the system.");
            }
    
            function failedCallback(error) {
                alert(error.get_message());
            }
    
            function logout() {
                Sys.Services.AuthenticationService.logout(
                    null,
                    logoutCompleted,
                    failedCallback,
                    null);
            }
    
            function logoutCompleted(result, userContext, methodName) {
                alert("You have logged out of the system");
            }
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager runat="server" ID="ScriptManager1">
                <Services>
                    <asp:ServiceReference Path="ProtectedService.asmx" />
                </Services>
            </asp:ScriptManager>
            <div>
                <input type="button" onclick="getRandom()" value="Get Random" />
                <hr />
                Name: <input type="text" id="txtName" /><br />
                Password: <input type="password" id="txtPassword" /><br />
                <input type="button" onclick="login()" value="Login" />
                <input type="button" onclick="logout()" value="Logout" />
            </div>
        </form>
    </body>
    </html>
    

    这个例子的用法是和我们上一个一样的,但是这里我们使用的是AJAX方式来验证

    Authentication Service属性

    • timeout属性:设置超时时间(Sys.Service.AuthecticationService.get_timtout()/set_timeout())
    • defaultLoginCompletedCallback//默认登陆成功
    • defaultLoginoutCompletedCallback//默认登出失败
    • defaultFailedCallback//错误

    Authentication Service实现

    Authentication Service的功能就是为我们提供一种以AJAX方式登陆和注销用户的功能,如果我们自己来实现,就会使用客户端调用WebService来实现这样的功能,而它给我们提供了更多的,比如跳转之类,实际上他的内部还是通过FormsAuthentication来实现的,他是对客户端执行服务器端方法给出一个特殊实现,调用了定义在程序集中的AuthenticationService类,最终工作的为Login(string,string.bol)和logout()两个方法

    Authentication Service扩展

    扩展AuthenticationService的功能,就是要改变用户认证的方式,在ASP.NET中与用户认证相关的模型就有Membership,正常情况下,我们扩展Membership,就可以实现这个功能了,但是事实上,如果我们要扩展一个Membership,就需要实现多达27个成员,

    那么我们就可以找到一个简便的方法 ,就是实现MembershipProvider的ValidateUser方法

    一个扩展Membership的示例

    创建一个类文件,名为SampleMembershipProvider.cs

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    
    
    public class SampleMembershipProvider : MembershipProvider
    {
        public override string ApplicationName
        {
            get
            {
                return "Sample Membership Provider";
            }
            set
            {
    
            }
        }
    
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override bool EnablePasswordReset
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override bool EnablePasswordRetrieval
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override int GetNumberOfUsersOnline()
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override string GetPassword(string username, string answer)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override string GetUserNameByEmail(string email)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override int MaxInvalidPasswordAttempts
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override int MinRequiredPasswordLength
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override int PasswordAttemptWindow
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override MembershipPasswordFormat PasswordFormat
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override string PasswordStrengthRegularExpression
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override bool RequiresQuestionAndAnswer
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override bool RequiresUniqueEmail
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
    
        public override string ResetPassword(string username, string answer)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override bool UnlockUser(string userName)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override void UpdateUser(MembershipUser user)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override bool ValidateUser(string username, string password)
        {
            if (username == "xiaoyaojian" && password == "123123..")
            {
                return true;
            }
    
            return false;
        }
    }
    

    我们继承了MembershipProvider,它是个抽象类,有好多方法要我们实现,实际上如果我们要简单实现,只需要重写他的ValidateUser类就可以了,所以我们只需要在那个方法里写如下代码

    if (username == "xiaoyaojian" && password == "123123.")
            {
                return true;
            }
    
            return false;
    

    定义好这个类以后,我们就需要在web.config中进行配置

    在<system.web>节点下添加如下内容

    <membership defaultProvider="SampleProvider">
            <providers>
              <add name="SampleProvider" type="SampleMembershipProvider"/>
            </providers>
          </membership>

    因为我们只实现了一个方法,所以就不要也不可以在配置中配置其他属性

    再次打开上面的页面,回发现只有在Name为“xiaoyaojian” Password为“123123..”的情况下,验证才会通过,也就是说,系统现在调用的是我们定义的membershipprovider

    如果扩展Authentication Service

    • 显然扩展ASP.NET功能相当复杂
    • 不如扩展Authentication Service,只需要实现两个方法
    • 有些时候我们不得不扩展它,因为扩展Membership只能修改用户信息的存储/验证方式,而不能真正改变认证方式

    那么,如果我们决定要这么做了,就需要写一个WebService,把它配置给ScriptManager,这个WebService主体结构如下

    [System.Web.Script.Services.ScriptService]
    public class SessionAuthenticationService : System.Web.Services.WebService
    {
        [WebMethod]
        public bool Login(string userName, string password, bool createPersistentCookie)
        {
          
        }
    
        [WebMethod]
        public void Logout()
        {
          
        }
    }

    注意:这里的参数列表包括参数名都必须与示例完全的相同

    一个扩展Authentication Service示例

    创建一个名为SessionAuthenticationService.asmx的WebService

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Security;
    
    /// <summary>
    ///SessionAuthenticationService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class SessionAuthenticationService : System.Web.Services.WebService
    {
        [WebMethod(EnableSession = true)]
        public bool Login(string userName, string password, bool createPersistentCookie)
        {
            if (Membership.Provider.ValidateUser(userName, password))
            {
                HttpContext.Current.Session["User"] = true;
                return true;
            }
            else
            {
                return false;
            }
        }
    
        [WebMethod]
        public void Logout()
        {
            HttpContext.Current.Session.Remove("User");
        }
    }
    
    

    然后我们再次修改上面的页面,

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="AuthService.aspx.cs" Inherits="Demo09_AuthService" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title></title>
        <script language="javascript" type="text/javascript">
            function getRandom() {
                ProtectedService.GetRandom(callback, failedCallback);
            }
    
            function callback(result) {
                alert(result);
            }
    
            function failedCallback(error) {
                alert(error.get_message());
            }
    
            function login() {
                Sys.Services.AuthenticationService.login(
                    document.getElementById("txtName").value,
                    document.getElementById("txtPassword").value,
                    false,
                    null,
                    null,
                    loginCompleted,
                    failedCallback,
                    null);
            }
    
            function loginCompleted(validCridentials, userContext, methodName) {
                alert(validCridentials ? "Congratulations!" : "Failed to login to the system.");
            }
    
            function failedCallback(error) {
                alert(error.get_message());
            }
    
            function logout() {
                Sys.Services.AuthenticationService.logout(
                    null,
                    logoutCompleted,
                    failedCallback,
                    null);
            }
    
            function logoutCompleted(result, userContext, methodName) {
                alert("You have logged out of the system");
            }
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager runat="server" ID="ScriptManager1">
                <Services>
                    <asp:ServiceReference Path="ProtectedService.asmx" />
                </Services>
                <AuthenticationService Path="~/Demo09/SessionAuthenticationService.asmx" />
            </asp:ScriptManager>
            <div>
                <input type="button" onclick="getRandom()" value="Get Random" />
                <hr />
                Name: <input type="text" id="txtName" /><br />
                Password: <input type="password" id="txtPassword" /><br />
                <input type="button" onclick="login()" value="Login" />
                <input type="button" onclick="logout()" value="Logout" />
            </div>
        </form>
    </body>
    </html>
    

    输入用户名xiaoyaojian密码123123..,点击Login,弹出成功的提示,但是我们点击GetRandom,是不会出现随机数的,因为我们没有执行FormsAuthentication.setAuthCookie,这也正好证明了我们扩展的AuthenticationService正常工作啦

  • 相关阅读:
    88. Merge Sorted Array
    87. Scramble String
    86. Partition List
    85. Maximal Rectangle
    84. Largest Rectangle in Histogram
    83. Remove Duplicates from Sorted List
    82. Remove Duplicates from Sorted List II
    81. Search in Rotated Sorted Array II
    80. Remove Duplicates from Sorted Array II
    计算几何——点线关系(叉积)poj2318
  • 原文地址:https://www.cnblogs.com/xiaoyaojian/p/2220575.html
Copyright © 2011-2022 走看看