• 如何在RIA Service中启用身份验证


    本文我将结合一个实例,一步一步地演示,然后在RIA Service中启用身份验证。包括在服务端的设计,和客户端的设计。

    本文实例源代码,可以通过下面地址下载

    https://files.cnblogs.com/chenxizhang/SilverlightRIAAuthenticationSample.rar

    1. 创建项目,并添加一个业务用的Domain Service

    作为演示,我们这里写了一个简单的方法

     
    namespace SilverlightRIAAuthenticationSample.Web
    {
        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.ComponentModel.DataAnnotations;
        using System.Linq;
        using System.ServiceModel.DomainServices.Hosting;
        using System.ServiceModel.DomainServices.Server;
        using System.Runtime.Serialization;
    
        // TODO: Create methods containing your application logic.
        [EnableClientAccess()]
        public class HomeDomainService : DomainService
        {
            [Query]
            /// <summary>
            /// 这个方法返回一些客户名称
            /// </summary>
            /// <returns></returns>
            public IQueryable<Customer> GetCustomers()
            {
                return new[]{
                    new Customer(){ID=1,Name="Microsoft"},
                    new Customer(){ID=2,Name="Google"},
                    new Customer(){ID=3,Name="Apple"},
                    new Customer(){ID=4,Name="Facebook"},
                    new Customer(){ID=5,Name="Yahoo"},
                    new Customer(){ID=16,Name="AOL"}
                }.AsQueryable();
            }
        }
    
        [DataContract]
        public class Customer
        {
            [Key][DataMember]
            public int ID { get; set; }
            [DataMember]
            public string Name { get; set; }
        }
    
    
    }
    
    
    

    写好之后,分别编译网站项目和Silverlight项目。在Silverlight中应该可以看到一个自动生成的类型

    image

    2. 编写客户端代码

    我简单地做了一个界面,用来显示由服务器返回的客户列表

    image

    <UserControl
        x:Class="SilverlightRIAAuthenticationSample.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
    
        <Grid
            x:Name="LayoutRoot"
            Background="White">
            <StackPanel>
                <TextBlock
                    Text="Customers List"
                    FontSize="40"></TextBlock>
    
                <ListBox
                    ItemsSource="{Binding}"
                    Padding="10" Margin="10">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock
                                Text="{Binding Name}"
                                FontSize="16"></TextBlock>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </StackPanel>
        </Grid>
    </UserControl>
    

    同时,编写一些简单的后台代码(直接写在xaml.cs中)

    using System.Windows;
    using System.Windows.Controls;
    using SilverlightRIAAuthenticationSample.Web;
    
    namespace SilverlightRIAAuthenticationSample
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
                Loaded += new RoutedEventHandler(MainPage_Loaded);
            }
    
            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                var ctx = new HomeDomainContext();
                var op=ctx.Load<Customer>(ctx.GetCustomersQuery());
                this.DataContext = op.Entities; 
            }
        }
    }
    

    运行起来,我们可以看到如下的一个效果

    image

    到这里为止,我们就已经实现了一个简单的Silverlight+RIA Service的场景。这不是本文的重点,我们下面要实现的是,在这个设计的基础上添加身份验证的功能。

    例如你可以假设一下:假如这个GetCustomers方法,并不是给所有用户都可以调用的,而是需要经过身份验证的用户才可以调用的

    3. 修改Web.config

    我们需要修改宿主网站的web.config,设置身份验证提供程序,可以选择Forms或者Windows,我们这里选择Forms,就是所谓的表单验证,客户端需要提供一个用户名和密码来进行验证

    image

    4. 添加一个AuthenticationDomainService

    在网站项目中

    image

    这个Domain Service不需要做任何修改。但也可以为User类型添加一些特殊的属性(称为Profile Property),这里先不展开了

    image

    但是,这里需要添加一个身份验证的提供程序。我写了一个最简单的MemberShipProvider

    请注意,SimpleMembershipProvider,只实现一个方法:ValidateUser(请注意代码的底部,红色部分)

    using System;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server.ApplicationServices;
    
    namespace SilverlightRIAAuthenticationSample.Web
    {
        [EnableClientAccess]
        public class AuthenticationDomainService : AuthenticationBase<User>
        {
            // To enable Forms/Windows Authentication for the Web Application, edit the appropriate section of web.config file.
        }
    
        public class User : UserBase
        {
            // NOTE: Profile properties can be added here 
            // To enable profiles, edit the appropriate section of web.config file.
    
            // public string MyProfileProperty { get; set; }
        }
    
        public class SimpleMembershipProvider : System.Web.Security.MembershipProvider
        {
    
            public override string ApplicationName
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }
    
            public override bool ChangePassword(string username, string oldPassword, string newPassword)
            {
                throw new NotImplementedException();
            }
    
            public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
            {
                throw new NotImplementedException();
            }
    
            public override System.Web.Security.MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out System.Web.Security.MembershipCreateStatus status)
            {
                throw new NotImplementedException();
            }
    
            public override bool DeleteUser(string username, bool deleteAllRelatedData)
            {
                throw new NotImplementedException();
            }
    
            public override bool EnablePasswordReset
            {
                get { throw new NotImplementedException(); }
            }
    
            public override bool EnablePasswordRetrieval
            {
                get { throw new NotImplementedException(); }
            }
    
            public override System.Web.Security.MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
            {
                throw new NotImplementedException();
            }
    
            public override System.Web.Security.MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
            {
                throw new NotImplementedException();
            }
    
            public override System.Web.Security.MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
            {
                throw new NotImplementedException();
            }
    
            public override int GetNumberOfUsersOnline()
            {
                throw new NotImplementedException();
            }
    
            public override string GetPassword(string username, string answer)
            {
                throw new NotImplementedException();
            }
    
            public override System.Web.Security.MembershipUser GetUser(string username, bool userIsOnline)
            {
                throw new NotImplementedException();
            }
    
            public override System.Web.Security.MembershipUser GetUser(object providerUserKey, bool userIsOnline)
            {
                throw new NotImplementedException();
            }
    
            public override string GetUserNameByEmail(string email)
            {
                throw new NotImplementedException();
            }
    
            public override int MaxInvalidPasswordAttempts
            {
                get { throw new NotImplementedException(); }
            }
    
            public override int MinRequiredNonAlphanumericCharacters
            {
                get { throw new NotImplementedException(); }
            }
    
            public override int MinRequiredPasswordLength
            {
                get { throw new NotImplementedException(); }
            }
    
            public override int PasswordAttemptWindow
            {
                get { throw new NotImplementedException(); }
            }
    
            public override System.Web.Security.MembershipPasswordFormat PasswordFormat
            {
                get { throw new NotImplementedException(); }
            }
    
            public override string PasswordStrengthRegularExpression
            {
                get { throw new NotImplementedException(); }
            }
    
            public override bool RequiresQuestionAndAnswer
            {
                get { throw new NotImplementedException(); }
            }
    
            public override bool RequiresUniqueEmail
            {
                get { throw new NotImplementedException(); }
            }
    
            public override string ResetPassword(string username, string answer)
            {
                throw new NotImplementedException();
            }
    
            public override bool UnlockUser(string userName)
            {
                throw new NotImplementedException();
            }
    
            public override void UpdateUser(System.Web.Security.MembershipUser user)
            {
                throw new NotImplementedException();
            }
    
            public override bool ValidateUser(string username, string password)
            {
                return username == "chenxizhang" && password == "password";
            }
        }
    }

    然后,我们还需要修改web.config,指定这个MembershipProvider,请注意下面的粗体部分

    <?xml version="1.0"?>
    
    <!--
      For more information on how to configure your ASP.NET application, please visit
      http://go.microsoft.com/fwlink/?LinkId=169433
      -->
    
    <configuration>
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
          <add name="DomainServiceModule" preCondition="managedHandler"
              type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </modules>
        <validation validateIntegratedModeConfiguration="false" />
      </system.webServer>
      <system.web>
        <httpModules>
          <add name="DomainServiceModule" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </httpModules>
        <compilation debug="true" targetFramework="4.0" />
        <authentication mode="Forms">
        </authentication>
    
        <membership defaultProvider="simple">
          <providers>
            <clear/>
            <add name="simple" type="SilverlightRIAAuthenticationSample.Web.SimpleMembershipProvider"/>
          </providers>
        </membership>
      </system.web>
      <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
            multipleSiteBindingsEnabled="true" />
      </system.serviceModel>
    </configuration>
    

    6. 如何在服务器端启用身份验证

    请注意下面代码的修改,在GetCustomers方法上面,我们添加一个RequiresAuthetication的Attribute。

    namespace SilverlightRIAAuthenticationSample.Web
    {
        using System.ComponentModel.DataAnnotations;
        using System.Linq;
        using System.Runtime.Serialization;
        using System.ServiceModel.DomainServices.Hosting;
        using System.ServiceModel.DomainServices.Server;
    
        // TODO: Create methods containing your application logic.
        [EnableClientAccess()]
        public class HomeDomainService : DomainService
        {
            [Query][RequiresAuthentication]
            /// <summary>
            /// 这个方法返回一些客户名称
            /// </summary>
            /// <returns></returns>
            public IQueryable<Customer> GetCustomers()
            {
                return new[]{
                    new Customer(){ID=1,Name="Microsoft"},
                    new Customer(){ID=2,Name="Google"},
                    new Customer(){ID=3,Name="Apple"},
                    new Customer(){ID=4,Name="Facebook"},
                    new Customer(){ID=5,Name="Yahoo"},
                    new Customer(){ID=16,Name="AOL"}
                }.AsQueryable();
            }
        }
    
        [DataContract]
        public class Customer
        {
            [Key][DataMember]
            public int ID { get; set; }
            [DataMember]
            public string Name { get; set; }
        }
    
    
    }
    
    

    到这里为止,服务器端的设计就完成了,我们可以将两个项目都重新生成一下

    然后,按下F5,重新运行一下Silverlight程序,不出意外的话,我们会看到下面一个错误

    image

    如果想要看到错误消息,可以对代码稍作修改

    using System.Windows;
    using System.Windows.Controls;
    using SilverlightRIAAuthenticationSample.Web;
    
    namespace SilverlightRIAAuthenticationSample
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
                Loaded += new RoutedEventHandler(MainPage_Loaded);
            }
    
            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                var ctx = new HomeDomainContext();
                var op = ctx.Load<Customer>(ctx.GetCustomersQuery(), (result) => {
                    if(result.HasError)
                    {
                        MessageBox.Show(result.Error.Message);
                        result.MarkErrorAsHandled();
                    }
                }, true);
                this.DataContext = op.Entities;
            }
        }
    }
    

    再次运行的话,就可以看到如下的消息提供

    image

    事情很清楚了,因为服务端要求要做身份验证,而客户端没有提供有关的用户信息,所以就报告了如上的错误

    7. 如何在客户端中使用身份验证

    有很多个做法可以实现客户端的身份验证,通常是用一个窗口让用户输入用户名和密码。

    为了简单起见,我先用最简单的方法来实现。我们可以修改App.xaml.cs文件

    using System;
    using System.ServiceModel.DomainServices.Client.ApplicationServices;
    using System.Windows;
    
    namespace SilverlightRIAAuthenticationSample
    {
        public partial class App : Application
        {
    
            public App()
            {
                this.Startup += this.Application_Startup;
                this.Exit += this.Application_Exit;
                this.UnhandledException += this.Application_UnhandledException;
    
                InitializeComponent();
    
                //创建一个上下文,这是在RIA Service中的一个对象
                var webcontext = new WebContext();
                webcontext.Authentication = new FormsAuthentication();
                this.ApplicationLifetimeObjects.Add(webcontext);
    
    
            }
    
            private void Application_Startup(object sender, StartupEventArgs e)
            {
    
                //直接使用硬编码的方式进行登录,注意这里是异步的
                var param = new LoginParameters("chenxizhang", "password"); 
                WebContext.Current.Authentication.Login(param, (op) =>
                {
                    if(op.User != null
                        && op.User.Identity.IsAuthenticated)
                        this.RootVisual = new MainPage();
                    else
                    {
                        MessageBox.Show("Login fail, please try again. ");
                    }
                }, null);
            }
    
            private void Application_Exit(object sender, EventArgs e)
            {
    
            }
    
            private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
            {
                // If the app is running outside of the debugger then report the exception using
                // the browser's exception mechanism. On IE this will display it a yellow alert 
                // icon in the status bar and Firefox will display a script error.
                if(!System.Diagnostics.Debugger.IsAttached)
                {
    
                    // NOTE: This will allow the application to continue running after an exception has been thrown
                    // but not handled. 
                    // For production applications this error handling should be replaced with something that will 
                    // report the error to the website and stop the application.
                    e.Handled = true;
                    Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
                }
            }
    
            private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
            {
                try
                {
                    string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
                    errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");
    
                    System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");
                }
                catch(Exception)
                {
                }
            }
        }
    }
    

    然后,再运行程序,我们就可以看到查询结果了

    image

    这就表示,我们已经登录成功了,所有后续代码就生效了。

    除了上面那种用代码方式在App类型的构造器实例化身份验证方式之外,还可以通过下面这样修改xaml来实现

    【备注】关于ApplicationLifetimeObjects,这是WPF和Silverlight的一个特殊功能,可以将一个对象在整个应用程序生命周期里面都有效,相当于是全局的对象。有兴趣可以参考这里的说明

    <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                 x:Class="SilverlightRIAAuthenticationSample.App"
                 xmlns:local="clr-namespace:SilverlightRIAAuthenticationSample"
                 xmlns:appsvc="clr-namespace:System.ServiceModel.DomainServices.Client.ApplicationServices;assembly=System.ServiceModel.DomainServices.Client.Web"
                 >
        <Application.Resources>
            
        </Application.Resources>
        <Application.ApplicationLifetimeObjects>
            <local:WebContext>
                <local:WebContext.Authentication>
                    <appsvc:FormsAuthentication></appsvc:FormsAuthentication>
                </local:WebContext.Authentication>
            </local:WebContext>
        </Application.ApplicationLifetimeObjects>
    </Application>
    

    8. 实现用户登录窗口

    接下来,我们实现一个简单的用户登录窗口吧。假设我们希望任何用户在使用这个程序之前,必须首先要登录

    image

    <controls:ChildWindow
        x:Class="SilverlightRIAAuthenticationSample.LoginWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
        Width="445"
        Height="227"
        Title="LoginWindow">
        <Grid
            x:Name="LayoutRoot"
            Margin="2">
    
            <Grid.Resources>
                <Style
                    TargetType="TextBlock">
                    <Setter
                        Property="FontSize"
                        Value="14"></Setter>
                    <Setter
                        Property="HorizontalAlignment"
                        Value="Right"></Setter>
                    <Setter
                        Property="Margin"
                        Value="5"></Setter>
                    <Setter
                        Property="VerticalAlignment"
                        Value="Center"></Setter>
                </Style>
    
                <Style
                    TargetType="TextBox">
                    <Setter
                        Property="VerticalAlignment"
                        Value="Center"></Setter>
                    <Setter
                        Property="Margin"
                        Value="5"></Setter>
                    <Setter
                        Property="Height"
                        Value="23"></Setter>
                </Style>
                <Style
                    TargetType="CheckBox">
                    <Setter
                        Property="Margin"
                        Value="5"></Setter>
                </Style>
            </Grid.Resources>
    
            <Grid.ColumnDefinitions>
                <ColumnDefinition
                    Width="150*" />
                <ColumnDefinition
                    Width="273*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition
                    Height="40" />
                <RowDefinition
                    Height="40" />
                <RowDefinition
                    Height="*" />
                <RowDefinition
                    Height="Auto" />
            </Grid.RowDefinitions>
    
            <TextBlock
                Text="UserName"></TextBlock>
            <TextBlock
                Text="Password"
                Grid.Row="1"></TextBlock>
    
            <TextBox
                Grid.Column="1"
                x:Name="txtUserName"></TextBox>
    
            <TextBox
                Grid.Row="1"
                Grid.Column="1"
                x:Name="txtPassword"></TextBox>
    
            <CheckBox
                Grid.Row="2"
                Grid.Column="1"
                Content="Remember me?"
                x:Name="chkRemember"></CheckBox>
    
    
            <Button
                x:Name="CancelButton"
                Content="Cancel"
                Click="CancelButton_Click"
                Width="75"
                Height="23"
                HorizontalAlignment="Right"
                Margin="0,12,0,0"
                Grid.Row="3"
                Grid.Column="1" />
            <Button
                x:Name="OKButton"
                Content="OK"
                Click="OKButton_Click"
                Width="75"
                Height="23"
                HorizontalAlignment="Right"
                Margin="0,12,79,0"
                Grid.Row="3"
                Grid.Column="1" />
        </Grid>
    </controls:ChildWindow>

    后台代码如下

    using System.ServiceModel.DomainServices.Client.ApplicationServices;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace SilverlightRIAAuthenticationSample
    {
        public partial class LoginWindow : ChildWindow
        {
            public LoginWindow()
            {
                InitializeComponent();
            }
    
            private void OKButton_Click(object sender, RoutedEventArgs e)
            {
    
                //直接使用硬编码的方式进行登录,注意这里是异步的
                var param = new LoginParameters(txtUserName.Text,txtPassword.Text);
                WebContext.Current.Authentication.Login(param, (op) =>
                {
                    if(op.User != null
                        && op.User.Identity.IsAuthenticated)
                    {
                        (App.Current.RootVisual as ContentControl).Content = new MainPage();
                        this.DialogResult = true;
                    }
                    else
                    {
                        MessageBox.Show("Login fail, please try again. ");
                        this.DialogResult = null;
                    }
                }, null);
    
    
            }
    
            private void CancelButton_Click(object sender, RoutedEventArgs e)
            {
                this.DialogResult = false;
            }
        }
    }
    
    

    接下来,我们需要对App.xaml.cs做点修改

    using System;
    using System.ServiceModel.DomainServices.Client.ApplicationServices;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace SilverlightRIAAuthenticationSample
    {
        public partial class App : Application
        {
    
            public App()
            {
                this.Startup += this.Application_Startup;
                this.Exit += this.Application_Exit;
                this.UnhandledException += this.Application_UnhandledException;
    
                InitializeComponent();
    
            }
    
            private void Application_Startup(object sender, StartupEventArgs e)
            {
    
                //使用用户登录对话框进行登录
                var content = new ContentControl()
                {
                    VerticalContentAlignment = System.Windows.VerticalAlignment.Stretch,
                    HorizontalContentAlignment = System.Windows.HorizontalAlignment.Stretch
                };
    
                content.Content = new TextBlock()
                {
                    Text = "Please login first",
                    FontSize = 50
                };
                this.RootVisual = content;
    
                var form = new LoginWindow();
                form.Show();
    
    
            }
    
            private void Application_Exit(object sender, EventArgs e)
            {
    
            }
    
            private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
            {
                // If the app is running outside of the debugger then report the exception using
                // the browser's exception mechanism. On IE this will display it a yellow alert 
                // icon in the status bar and Firefox will display a script error.
                if(!System.Diagnostics.Debugger.IsAttached)
                {
    
                    // NOTE: This will allow the application to continue running after an exception has been thrown
                    // but not handled. 
                    // For production applications this error handling should be replaced with something that will 
                    // report the error to the website and stop the application.
                    e.Handled = true;
                    Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
                }
            }
    
            private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
            {
                try
                {
                    string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
                    errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");
    
                    System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");
                }
                catch(Exception)
                {
                }
            }
        }
    }
    

    这两段代码的意思是,先启动LoginWindow,然后根据用户输入的信息进行登录,成功的话,就显示主窗口,调试起来看的效果如下

    image

    输入用户名和密码,例如

    image

    然后点击“Ok”,因为我提供的用户是合法的,所以会显示MainPage

    image

    如果我提供的用户信息不合法呢?

    image

    一点都不意外,我们将收到一个提示

    image

    9.实现用户自动登录

    假设我们希望这个程序能够实现用户的自动登录,也就是说不要每次都输入用户名和密码,该怎么办呢?

            private void Application_Startup(object sender, StartupEventArgs e)
            {
                ///用LoadUser方法可以自动将保存在本地的用户凭据去做身份验证
                WebContext.Current.Authentication.LoadUser((result) => {
    
                    if(result.User != null && result.User.Identity.IsAuthenticated)
                    {//如果成功的话,就直接显示MainPage
                        this.RootVisual = new MainPage();
                    }
                    else
                    {
                        //使用用户登录对话框进行登录
                        var content = new ContentControl()
                        {
                            VerticalContentAlignment = System.Windows.VerticalAlignment.Stretch,
                            HorizontalContentAlignment = System.Windows.HorizontalAlignment.Stretch
                        };
    
                        content.Content = new TextBlock()
                        {
                            Text = "Please login first",
                            FontSize = 50
                        };
                        this.RootVisual = content;
    
                        var form = new LoginWindow();
                        form.Show();
    
                    }
                }, null);
            }
    
     

    同时,我们还需要修改LoginWindow,让他可以保存用户凭据(你是否记得我们在那个窗口上有一个复选框呢?),请注意下面红色的部分

           private void OKButton_Click(object sender, RoutedEventArgs e)
            {
    
                //直接使用硬编码的方式进行登录,注意这里是异步的
                var param = new LoginParameters(
                    txtUserName.Text, 
                    txtPassword.Text, 
                    (bool)chkRemember.IsChecked, 
                    string.Empty);
    
                WebContext.Current.Authentication.Login(param, (op) =>
                {
                    if(op.User != null
                        && op.User.Identity.IsAuthenticated)
                    {
                        (App.Current.RootVisual as ContentControl).Content = new MainPage();
                        this.DialogResult = true;
                    }
                    else
                    {
                        MessageBox.Show("Login fail, please try again. ");
                        this.DialogResult = null;
                    }
                }, null);
    
    
            }
     
     

    这样修改完之后,重新运行项目,第一次的时候,因为本地没有保存凭据,所以我们会被要求进行登录

    image

    请注意,我们选中“Remember me”,然后点击“Ok”

    image

    然后,我们可以关掉浏览器,重新启动程序。因为之前保存了用户凭据,所以你将直接可以看到MainPage,而无需登录

    image

    很不错,对吧?最后遗留了一个问题,就是如果我想用其他用户登录的话,怎么办呢?我肯定希望将原先保存好的用户凭据删除掉。如何实现这样的功能呢?

    10. 实现用户注销

                <HyperlinkButton
                    Content="Logout"
                    HorizontalAlignment="Right" Margin="10" x:Name="btLogout" Click="btLogout_Click"></HyperlinkButton>
    
                    <TextBlock
                    Text="Customers List"
                    FontSize="40"></TextBlock>

    为了实现注销,我们一般在主窗口上面,添加一个HyperLinkButton,如上所示。它的代码也很简单

            private void btLogout_Click(object sender, RoutedEventArgs e)
            {
                WebContext.Current.Authentication.Logout(true);
            }

    11.总结

    本文,我用一个实例讲解了如何在RIA Service中启用身份验证。这是很实用的技术,我们使用到了Authentication Domain Service,和自定义的MembershipProvider,在客户端我们还实现了登录窗口以及自动登录。

    本文实例源代码,可以通过下面地址下载

    https://files.cnblogs.com/chenxizhang/SilverlightRIAAuthenticationSample.rar

  • 相关阅读:
    Weblogic任意文件上传漏洞(CVE-2018-2894)复现
    Angular动态创建组件之Portals
    nodejs 开发企业微信第三方应用入门教程
    系列文章|OKR与敏捷(三):赋予团队自主权
    Angular开发技巧
    系列文章|OKR与敏捷(二):实现全栈敏捷
    系列文章|OKR与敏捷(一):瀑布式目标与敏捷的冲突
    OKR与Scrum如何强强联手
    Service Worker
    RxJS 实现摩斯密码(Morse) 【内附脑图】
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/2105204.html
Copyright © 2020-2023  润新知