Java内部类详解起名

透过前两篇小说,测度大家对WIF已经有相比足够的认识了,估算大家在通过了干燥的论争之后,肯定是跃跃欲试赶紧付诸于行动了。起名 1不能够,咱们程序员正是以此疾病。那好吧,笔者也不那么多废话了,直接进去正题吧。

Java内部类详解

咱们接下去的demo将席卷以下的工程:

  谈起内部类这一个词,想必很两个人都不面生,不过又会认为不纯熟。原因是平时编辑代码时大概用到的现象不多,用得最多的是在有事件监听的情事下,并且即利用到也很少去总括内部类的用法。前天大家就来1探毕竟。上面是本文的目录大纲:

 

  一.内品种基础

  1. SiteA —— 基于.net framework 4.5的MVC 4程序,使用WIF
    4.5的SDK,第一个RP
  2. SiteB —— 基于.net framework 4.5的MVC 4程序,使用WIF
    3.5的SDK,第二个RP
  3. SiteC —— 基于.net framework 4.0的MVC 4程序,使用WIF
    3.5的SDK,第三个RP
  4. SiteD —— 基于.net framework 4.0 的WebApplication程序,使用WIF
    3.5的SDK,第四个RP
  5. STS —— 基于.net framework 4.5 的MVC 4程序,作为IP

  二.时刻不忘通晓个中类

 

  三.内项目标采取情形和利益

 

  4.广大的与其间类相关的笔试面试题

1、创制第壹个昂CoraP

以管理员身份打开vs2013,在开头页上点击“新建项目”,在左手的“模板”树下,展开“其余门类项目”,然后选择“Visual
Studio消除方案”,“名称”输入框里输入WIFSSO,然后选拔消除方案的路径后点击”鲜明“,如图:

起名 2

在”消除方案能源管理器“中,在新建好的消除方案上点右键,选用”添加“->”新建项目“。在弹出的对话框中挑选”ASP.NET
MVC 4 Web应用程序“,记得.Net
Framework版本选4.5,名称起名字为”SiteA“,然后点显著,如图:

起名 3

在弹出的“新ASP.NET MVC
四项目”对话框中央直机关接点“明确”,第二个RubiconP项目新建实现后,添加以下五个引用:System.IdentityModel和System.IdentityModel.Services。本次的教程不选拔Identity
and Access
Tool,而是直接修改web.config文件,这样能使我们对WIF的布局有更透彻的问询。

起名,打开web.config文件,将configSections节里的entityFramework配置节点删掉,因为大家不需求用到Entity
Framework。最佳把web.config中关于Entity
Framework相关的配备全都删掉,因为我们都用不上。然后加上以下那多个节点:

 

[html] view
plain
copyprint?

  1. <section name=”system.identityModel” type=”System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089″ />  
  2.    <section name=”system.identityModel.services” type=”System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089″ />  

    <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    

将authentication节的mode属性设为None,并把内部的form节点删掉,因为我们使用的是WIF的身份验证方式,而不是价值观的Forms身份验证。然后扩张authorization节点,不一样意匿名用户访问站点:

 

 

[html] view
plain
copyprint?

  1. <authorization>  
  2.   <deny users=”?”/>  
  3. </authorization>  

    <authorization>
      <deny users="?"/>
    </authorization>
    

在system.webServer节点下增添1个HttpModule的安插节点:

 

 

[html] view
plain
copyprint?

  1. <modules>  
  2.   <add name=”WSFederationAuthenticationModule” type=”System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″ preCondition=”managedHandler” />  
  3.   <add name=”SessionAuthenticationModule” type=”System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″ preCondition=”managedHandler” />  
  4. </modules>  

    <modules>
      <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
    </modules>
    

终极,扩张WIF的布署节点:

 

 

[html] view
plain
copyprint?

  1. <system.identityModel>  
  2.   <identityConfiguration>  
  3.     <audienceUris mode=”Always”>  
  4.       <add value=”http://www.sitea.com” />  
  5.     </audienceUris>  
  6.     <issuerNameRegistry type=”System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″>  
  7.       <trustedIssuers>  
  8.         <add name=”http://www.sts.com” thumbprint=”FD1425A2F30937786F46E52E43B01AFD54E5D64D”/>  
  9.       </trustedIssuers>  
  10.     </issuerNameRegistry>  
  11.   </identityConfiguration>  
  12. </system.identityModel>  
  13. <system.identityModel.services>  
  14.   <federationConfiguration>  
  15.     <cookieHandler requireSsl=”false” />  
  16.     <wsFederation passiveRedirectEnabled=”true” issuer=”http://www.sts.com” realm=”http://www.sitea.com” reply=”http://www.sitea.com” requireHttps=”false”/>  
  17.   </federationConfiguration>  
  18. </system.identityModel.services>  

    <identityConfiguration>
      <audienceUris mode="Always">
        <add value="http://www.sitea.com" />
      </audienceUris>
      <issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <trustedIssuers>
          <add name="http://www.sts.com" thumbprint="FD1425A2F30937786F46E52E43B01AFD54E5D64D"/>
        </trustedIssuers>
      </issuerNameRegistry>
    </identityConfiguration>
    


    <federationConfiguration>
      <cookieHandler requireSsl="false" />
      <wsFederation passiveRedirectEnabled="true" issuer="http://www.sts.com" realm="http://www.sitea.com" reply="http://www.sitea.com" requireHttps="false"/>
    </federationConfiguration>
    

本人来详细解释一下那几个节点的意义。audienceUris钦点了一组能够被PAJEROP接受的地点标识U安德拉I,唯有这么些布置中的UXC90I范围内的令牌才方可被接受。那里,作者把siteA配置在此间。trustedIssuers就是受注重的发行者,由于大家以此demo未有应用SSL,所以那里本身钦命的thumbprint是IIS
Express的螺纹,那么些指纹在哪儿能够赢得呢?打开IIS管理器,在左侧树点击根节点,然后在“功效视图”里双击“服务器证书”,如下图:

起名 4

在开拓的评释列表里,找到IIS Express Development
Certificate,双击,在弹出的”证书“对话框中点击“详细音信”页签,找到“指纹”然后点击,把框里的螺纹拷下来,全都改成大写后粘贴到thumbnail的值里去:

起名 5

接下去配置federationConfiguration节点,它表示配置WSFederationAuthenticationModule (WSFAM) 
SessionAuthenticationModule (SAM) 
时选拔联合身份验证通过的 WS 联合身份验证协议。那里大家采纳WS
联合身份验证的身份验证模块
(WSFAM),关于该节点的事无巨细安顿音讯,请参考:http://msdn.microsoft.com/zh-cn/library/office/apps/hh568665.aspx

好,这样一来,SiteA的布署就早已实现了,然后大家来加点代码。

开辟/Views/Home/Index.cshtml,将原始的代码删掉,改为如下代码:

 

[html] view
plain
copyprint?

  1. @using System.Security.Claims  
  2. @{  
  3.     ViewBag.Title = “SiteA主页”;  
  4.     ClaimsIdentity ci = User.Identity as ClaimsIdentity;  
  5.     if(ci!=null)  
  6.     {  
  7.         <h2>@ci.FindFirst(ClaimTypes.Name).Value</h2>  
  8.         <h2>@ci.FindFirst(ClaimTypes.Email).Value</h2>  
  9.     }  
  10. }  
  11.   
  12. <a href=”http://www.sts.com/Account/LogOff"&gt;退出&lt;/a&gt;  

    @using System.Security.Claims
    @{

    ViewBag.Title = "SiteA主页";
    ClaimsIdentity ci = User.Identity as ClaimsIdentity;
    if(ci!=null)
    {
        <h2>@ci.FindFirst(ClaimTypes.Name).Value</h2>
        <h2>@ci.FindFirst(ClaimTypes.Email).Value</h2>
    }
    

    }

    退出

代码非常粗略,只要当前用户处于已报到状态,就把用户的称号和Email显示在页面上。

 

迄今停止,SiteA就已经到位了。你是或不是着急的想要运维了吗?别急,就算有SiteA了,但还未曾STS呢,今后起始SiteA,由于没登录,所以它会跳转到STS,但STS还不设有,所以会出错的。

 

  若有不正之处,请多包涵并欢迎批评指正。

二、创建STS

接下去大家来创设STS,在消除方案上新建项目,新建二个名叫STS的MVC
4应用程序,.Net
Framework选取4.5,项目模板采用“Internet应用程序”,分明。

添加System.IdentityModel和System.IdentityModel.Services那七个引用,打开web.config,为forms节点添加五个属性:

 

[html] view
plain
copyprint?

  1. <forms loginUrl=”~/Account/Login” timeout=”2880″ slidingExpiration=”true” name=”.STSASPAUTH” />  

在AppSettings里扩大如下四个节点:

 

 

[html] view
plain
copyprint?

  1. <add key=”IssuerName” value=”PassiveSigninSTS” />  
  2. <add key=”SigningCertificateName” value=”CN=localhost” />  
  3. <add key=”EncryptingCertificateName” value=”” />  

    <add key="IssuerName" value="PassiveSigninSTS" />
    <add key="SigningCertificateName" value="CN=localhost" />
    <add key="EncryptingCertificateName" value="" />
    

1致禁止匿名用户访问:

 

 

[html] view
plain
copyprint?

  1. <authorization>  
  2.   <deny users=”?”/>  
  3. </authorization>  

    <authorization>
      <deny users="?"/>
    </authorization>
    

在应用程序下新建一个名称叫Services的文书夹,在中间新建两个类公事,名叫:CertificateUtil,用于获取证书,具体代码如下:

 

 

[csharp] view
plain
copyprint?

  1. public class CertificateUtil  
  2. {  
  3.     public static X509Certificate2 GetCertificate(StoreName name, StoreLocation location, string subjectName)  
  4.     {  
  5.         X509Store store = new X509Store(name, location);  
  6.         X509Certificate2Collection certificates = null;  
  7.         store.Open(OpenFlags.ReadOnly);  
  8.   
  9.         try  
  10.         {  
  11.             X509Certificate2 result = null;  
  12.             certificates = store.Certificates;  
  13.   
  14.             for (int i = 0; i < certificates.Count; i++)  
  15.             {  
  16.                 X509Certificate2 cert = certificates[i];  
  17.                 if (cert.SubjectName.Name.ToLower() == subjectName.ToLower())  
  18.                 {  
  19.                     if (result != null)  
  20.                         throw new ApplicationException(string.Format(“subject Name {0}存在三个注明”, subjectName));  
  21.                     result = new X509Certificate2(cert);  
  22.                 }  
  23.             }  
  24.   
  25.             if (result == null)  
  26.             {  
  27.                 throw new ApplicationException(string.Format(“未有找到用于 subject Name {0} 的注解”, subjectName));  
  28.             }  
  29.   
  30.             return result;  
  31.         }  
  32.         finally  
  33.         {  
  34.             if (certificates != null)  
  35.             {  
  36.                 for (int i = 0; i < certificates.Count; i++)  
  37.                 {  
  38.                     certificates[i].Reset();  
  39.                 }  
  40.             }  
  41.             store.Close();  
  42.         }  
  43.     }  
  44.   
  45. }  

    public class CertificateUtil
    {
        public static X509Certificate2 GetCertificate(StoreName name, StoreLocation location, string subjectName)
        {
            X509Store store = new X509Store(name, location);
            X509Certificate2Collection certificates = null;
            store.Open(OpenFlags.ReadOnly);
    
            try
            {
                X509Certificate2 result = null;
                certificates = store.Certificates;
    
                for (int i = 0; i < certificates.Count; i++)
                {
                    X509Certificate2 cert = certificates[i];
                    if (cert.SubjectName.Name.ToLower() == subjectName.ToLower())
                    {
                        if (result != null)
                            throw new ApplicationException(string.Format("subject Name {0}存在多个证书", subjectName));
                        result = new X509Certificate2(cert);
                    }
                }
    
                if (result == null)
                {
                    throw new ApplicationException(string.Format("没有找到用于 subject Name {0} 的证书", subjectName));
                }
    
                return result;
            }
            finally
            {
                if (certificates != null)
                {
                    for (int i = 0; i < certificates.Count; i++)
                    {
                        certificates[i].Reset();
                    }
                }
                store.Close();
            }
        }
    
    }
    

 

创办新类,名叫Common,存放多少个常量:

 

[csharp] view
plain
copyprint?

  1. public class Common  
  2. {  
  3.     public const string IssuerName = “IssuerName”;  
  4.     public const string SigningCertificateName = “SigningCertificateName”;  
  5.     public const string EncryptingCertificateName = “EncryptingCertificateName”;  
  6.   
  7. }  

    public class Common
    {
        public const string IssuerName = "IssuerName";
        public const string SigningCertificateName = "SigningCertificateName";
        public const string EncryptingCertificateName = "EncryptingCertificateName";
    
    }
    

开立异类,名叫SingleSignOnManager,用于注册奥迪Q叁P以及得到TucsonP列表:

 

 

[csharp] view
plain
copyprint?

  1. public class SingleSignOnManager  
  2. {  
  3.     const string SITECOOKIENAME = “StsSiteCookie”;  
  4.     const string SITENAME = “StsSite”;  
  5.   
  6.     /// <summary>  
  7.     /// Returns a list of sites the user is logged in via the STS  
  8.     /// </summary>  
  9.     /// <returns></returns>  
  10.     public static string[] SignOut()  
  11.     {  
  12.         if (HttpContext.Current != null &&  
  13.              HttpContext.Current.Request != null &&  
  14.              HttpContext.Current.Request.Cookies != null  
  15.             )  
  16.         {  
  17.             HttpCookie siteCookie =  
  18.                 HttpContext.Current.Request.Cookies[SITECOOKIENAME];  
  19.   
  20.             if (siteCookie != null)  
  21.                 return siteCookie.Values.GetValues(SITENAME);  
  22.         }  
  23.   
  24.         return new string[0];  
  25.     }  
  26.   
  27.     public static void RegisterRP(string SiteUrl)  
  28.     {  
  29.         if (HttpContext.Current != null &&  
  30.              HttpContext.Current.Request != null &&  
  31.              HttpContext.Current.Request.Cookies != null  
  32.             )  
  33.         {  
  34.             // get an existing cookie or create a new one  
  35.             HttpCookie siteCookie =  
  36.                 HttpContext.Current.Request.Cookies[SITECOOKIENAME];  
  37.             if (siteCookie == null)  
  38.                 siteCookie = new HttpCookie(SITECOOKIENAME);  
  39.   
  40.             siteCookie.Values.Add(SITENAME, SiteUrl);  
  41.   
  42.             HttpContext.Current.Response.AppendCookie(siteCookie);  
  43.         }  
  44.     }  
  45.   
  46. }  

    public class SingleSignOnManager
    {
        const string SITECOOKIENAME = "StsSiteCookie";
        const string SITENAME = "StsSite";
    
        /// <summary>
        /// Returns a list of sites the user is logged in via the STS
        /// </summary>
        /// <returns></returns>
        public static string[] SignOut()
        {
            if (HttpContext.Current != null &&
                 HttpContext.Current.Request != null &&
                 HttpContext.Current.Request.Cookies != null
                )
            {
                HttpCookie siteCookie =
                    HttpContext.Current.Request.Cookies[SITECOOKIENAME];
    
                if (siteCookie != null)
                    return siteCookie.Values.GetValues(SITENAME);
            }
    
            return new string[0];
        }
    
        public static void RegisterRP(string SiteUrl)
        {
            if (HttpContext.Current != null &&
                 HttpContext.Current.Request != null &&
                 HttpContext.Current.Request.Cookies != null
                )
            {
                // get an existing cookie or create a new one
                HttpCookie siteCookie =
                    HttpContext.Current.Request.Cookies[SITECOOKIENAME];
                if (siteCookie == null)
                    siteCookie = new HttpCookie(SITECOOKIENAME);
    
                siteCookie.Values.Add(SITENAME, SiteUrl);
    
                HttpContext.Current.Response.AppendCookie(siteCookie);
            }
        }
    
    }
    

始建新类,CustomSecurityTokenService,自定义令牌服务,继承SecurityTokenService,用于再次来到须要的注解令牌:

 

 

[csharp] view
plain
copyprint?

  1. public class CustomSecurityTokenService : SecurityTokenService  
  2. {  
  3.     private readonly SigningCredentials signingCreds;  
  4.     private readonly EncryptingCredentials encryptingCreds;  
  5.   
  6.     public CustomSecurityTokenService(SecurityTokenServiceConfiguration config)  
  7.         : base(config)  
  8.     {  
  9.         this.signingCreds = new X509SigningCredentials(  
  10.             CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, WebConfigurationManager.AppSettings[Common.SigningCertificateName]));  
  11.   
  12.         if (!string.IsNullOrWhiteSpace(WebConfigurationManager.AppSettings[Common.EncryptingCertificateName]))  
  13.         {  
  14.             this.encryptingCreds = new X509EncryptingCredentials(  
  15.                 CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, WebConfigurationManager.AppSettings[Common.EncryptingCertificateName]));  
  16.         }  
  17.     }  
  18.   
  19.     /// <summary>  
  20.     /// 此措施重回要表露的令牌内容。内容由1组ClaimsIdentity实例来代表,每贰个实例对应了1个要宣布的令牌。当前Windows Identity Foundation只帮助单个令牌宣布,由此回到的集纳必须一连只含有单个实例。  
  21.     /// </summary>  
  22.     /// <param name=”principal”>调用方的principal</param>  
  23.     /// <param name=”request”>进入的 RubiconST,我们那里并非它</param>  
  24.     /// <param name=”scope”>由事先经过GetScope方法重返的限制</param>  
  25.     /// <returns></returns>  
  26.     protected override ClaimsIdentity GetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope)  
  27.     {  
  28.         //再次来到贰个暗中同意表明集,里面了包蕴自身想要的扬言  
  29.         //那里您能够经过ClaimsPrincipal来验证用户,并透过它来回到正确的扬言。  
  30.         string identityName = principal.Identity.Name;  
  31.         string[] temp = identityName.Split(‘|’);  
  32.         ClaimsIdentity outgoingIdentity = new ClaimsIdentity();  
  33.         outgoingIdentity.AddClaim(new Claim(ClaimTypes.Email, temp[0]));  
  34.         outgoingIdentity.AddClaim(new Claim(ClaimTypes.DateOfBirth, temp[1]));  
  35.         outgoingIdentity.AddClaim(new Claim(ClaimTypes.Name, temp[2]));  
  36.         SingleSignOnManager.RegisterRP(scope.AppliesToAddress);  
  37.         return outgoingIdentity;  
  38.     }  
  39.   
  40.     /// <summary>  
  41.     /// 此方式再次回到用于令牌公布请求的布署。配置由Scope类表示。在此地,大家只发表令牌到1个由encryptingCreds字段表示的LANDP标识        /// </summary>  
  42.     /// <param name=”principal”></param>  
  43.     /// <param name=”request”></param>  
  44.     /// <returns></returns>  
  45.     protected override Scope GetScope(ClaimsPrincipal principal, RequestSecurityToken request)  
  46.     {  
  47.         // 使用request的AppliesTo属性和BMWX5P标识来创设Scope  
  48.         Scope scope = new Scope(request.AppliesTo.Uri.AbsoluteUri, this.signingCreds);  
  49.   
  50.         if (Uri.IsWellFormedUriString(request.ReplyTo, UriKind.Absolute))  
  51.         {  
  52.             if (request.AppliesTo.Uri.Host != new Uri(request.ReplyTo).Host)  
  53.                 scope.ReplyToAddress = request.AppliesTo.Uri.AbsoluteUri;  
  54.             else  
  55.                 scope.ReplyToAddress = request.ReplyTo;  
  56.         }  
  57.         else  
  58.         {  
  59.             Uri resultUri = null;  
  60.             if (Uri.TryCreate(request.AppliesTo.Uri, request.ReplyTo, out resultUri))  
  61.                 scope.ReplyToAddress = resultUri.AbsoluteUri;  
  62.             else  
  63.                 scope.ReplyToAddress = request.AppliesTo.Uri.ToString();  
  64.         }  
  65.         if (this.encryptingCreds != null)  
  66.         {  
  67.             // 借使STS对应几个LX570P,要选拔证书内定到请求令牌的奥迪Q五P,然后再用 encryptingCreds   
  68.             scope.EncryptingCredentials = this.encryptingCreds;  
  69.         }  
  70.         else  
  71.             scope.TokenEncryptionRequired = false;  
  72.         return scope;  
  73.     }  
  74. }  

    public class CustomSecurityTokenService : SecurityTokenService
    {
        private readonly SigningCredentials signingCreds;
        private readonly EncryptingCredentials encryptingCreds;
    
        public CustomSecurityTokenService(SecurityTokenServiceConfiguration config)
            : base(config)
        {
            this.signingCreds = new X509SigningCredentials(
                CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, WebConfigurationManager.AppSettings[Common.SigningCertificateName]));
    
            if (!string.IsNullOrWhiteSpace(WebConfigurationManager.AppSettings[Common.EncryptingCertificateName]))
            {
                this.encryptingCreds = new X509EncryptingCredentials(
                    CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, WebConfigurationManager.AppSettings[Common.EncryptingCertificateName]));
            }
        }
    
        /// <summary>
        /// 此方法返回要发布的令牌内容。内容由一组ClaimsIdentity实例来表示,每一个实例对应了一个要发布的令牌。当前Windows Identity Foundation只支持单个令牌发布,因此返回的集合必须总是只包含单个实例。
        /// </summary>
        /// <param name="principal">调用方的principal</param>
        /// <param name="request">进入的 RST,我们这里不用它</param>
        /// <param name="scope">由之前通过GetScope方法返回的范围</param>
        /// <returns></returns>
        protected override ClaimsIdentity GetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope)
        {
            //返回一个默认声明集,里面了包含自己想要的声明
            //这里你可以通过ClaimsPrincipal来验证用户,并通过它来返回正确的声明。
            string identityName = principal.Identity.Name;
            string[] temp = identityName.Split('|');
            ClaimsIdentity outgoingIdentity = new ClaimsIdentity();
            outgoingIdentity.AddClaim(new Claim(ClaimTypes.Email, temp[0]));
            outgoingIdentity.AddClaim(new Claim(ClaimTypes.DateOfBirth, temp[1]));
            outgoingIdentity.AddClaim(new Claim(ClaimTypes.Name, temp[2]));
            SingleSignOnManager.RegisterRP(scope.AppliesToAddress);
            return outgoingIdentity;
        }
    
        /// <summary>
        /// 此方法返回用于令牌发布请求的配置。配置由Scope类表示。在这里,我们只发布令牌到一个由encryptingCreds字段表示的RP标识        /// </summary>
        /// <param name="principal"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        protected override Scope GetScope(ClaimsPrincipal principal, RequestSecurityToken request)
        {
            // 使用request的AppliesTo属性和RP标识来创建Scope
            Scope scope = new Scope(request.AppliesTo.Uri.AbsoluteUri, this.signingCreds);
    
            if (Uri.IsWellFormedUriString(request.ReplyTo, UriKind.Absolute))
            {
                if (request.AppliesTo.Uri.Host != new Uri(request.ReplyTo).Host)
                    scope.ReplyToAddress = request.AppliesTo.Uri.AbsoluteUri;
                else
                    scope.ReplyToAddress = request.ReplyTo;
            }
            else
            {
                Uri resultUri = null;
                if (Uri.TryCreate(request.AppliesTo.Uri, request.ReplyTo, out resultUri))
                    scope.ReplyToAddress = resultUri.AbsoluteUri;
                else
                    scope.ReplyToAddress = request.AppliesTo.Uri.ToString();
            }
            if (this.encryptingCreds != null)
            {
                // 如果STS对应多个RP,要选择证书指定到请求令牌的RP,然后再用 encryptingCreds 
                scope.EncryptingCredentials = this.encryptingCreds;
            }
            else
                scope.TokenEncryptionRequired = false;
            return scope;
        }
    }
    

最后添加新类CustomSecurityTokenServiceConfiguration,继承SecurityTokenServiceConfiguration:

 

 

[csharp] view
plain
copyprint?

  1. public class CustomSecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration  
  2. {  
  3.     private static readonly object syncRoot = new object();  
  4.     private const string CustomSecurityTokenServiceConfigurationKey = “CustomSecurityTokenServiceConfigurationKey”;  
  5.   
  6.     public CustomSecurityTokenServiceConfiguration()  
  7.         : base(WebConfigurationManager.AppSettings[Common.IssuerName])  
  8.     {  
  9.         this.SecurityTokenService = typeof(CustomSecurityTokenService);  
  10.     }  
  11.   
  12.     public static CustomSecurityTokenServiceConfiguration Current  
  13.     {  
  14.         get  
  15.         {  
  16.             HttpApplicationState app = HttpContext.Current.Application;  
  17.             CustomSecurityTokenServiceConfiguration config = app.Get(CustomSecurityTokenServiceConfigurationKey) as CustomSecurityTokenServiceConfiguration;  
  18.             if (config != null)  
  19.                 return config;  
  20.             lock (syncRoot)  
  21.             {  
  22.                 config = app.Get(CustomSecurityTokenServiceConfigurationKey) as CustomSecurityTokenServiceConfiguration;  
  23.                 if (config == null)  
  24.                 {  
  25.                     config = new CustomSecurityTokenServiceConfiguration();  
  26.                     app.Add(CustomSecurityTokenServiceConfigurationKey, config);  
  27.                 }  
  28.   
  29.                 return config;  
  30.             }  
  31.         }  
  32.     }  
  33. }  

    public class CustomSecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration
    {
        private static readonly object syncRoot = new object();
        private const string CustomSecurityTokenServiceConfigurationKey = "CustomSecurityTokenServiceConfigurationKey";
    
        public CustomSecurityTokenServiceConfiguration()
            : base(WebConfigurationManager.AppSettings[Common.IssuerName])
        {
            this.SecurityTokenService = typeof(CustomSecurityTokenService);
        }
    
        public static CustomSecurityTokenServiceConfiguration Current
        {
            get
            {
                HttpApplicationState app = HttpContext.Current.Application;
                CustomSecurityTokenServiceConfiguration config = app.Get(CustomSecurityTokenServiceConfigurationKey) as CustomSecurityTokenServiceConfiguration;
                if (config != null)
                    return config;
                lock (syncRoot)
                {
                    config = app.Get(CustomSecurityTokenServiceConfigurationKey) as CustomSecurityTokenServiceConfiguration;
                    if (config == null)
                    {
                        config = new CustomSecurityTokenServiceConfiguration();
                        app.Add(CustomSecurityTokenServiceConfigurationKey, config);
                    }
    
                    return config;
                }
            }
        }
    }
    

开拓/Controllers/HomeController.cs,将Index()方法修改如下:

 

 

[csharp] view
plain
copyprint?

  1. public ActionResult Index()  
  2. {  
  3.     FederatedPassiveSecurityTokenServiceOperations.ProcessRequest(  
  4.         System.Web.HttpContext.Current.Request,  
  5.         User as ClaimsPrincipal,  
  6.         CustomSecurityTokenServiceConfiguration.Current.CreateSecurityTokenService(),  
  7.         System.Web.HttpContext.Current.Response);  
  8.     return View();  
  9. }  

        public ActionResult Index()
        {
            FederatedPassiveSecurityTokenServiceOperations.ProcessRequest(
                System.Web.HttpContext.Current.Request,
                User as ClaimsPrincipal,
                CustomSecurityTokenServiceConfiguration.Current.CreateSecurityTokenService(),
                System.Web.HttpContext.Current.Response);
            return View();
        }
    

开拓/Controllers/AccountController.cs,将Login(LoginModel model, string
returnUrl)方法修改如下:

 

 

[csharp] view
plain
copyprint?

  1.         [HttpPost]  
  2.         [AllowAnonymous]  
  3.         [ValidateAntiForgeryToken]  
  4.         public ActionResult Login(LoginModel model, string returnUrl)  
  5.         {  
  6.             var query = HttpUtility.ParseQueryString(Request.UrlReferrer.Query);  
  7.             if (model.UserName == “ojlovecd@csdn.net” && model.Password == “123456”)  
  8.             {  
  9.                 FormsAuthentication.SetAuthCookie(“ojlovecd@csdn.net|1983-10-22|oujian”, false);  
  10.                 if (!string.IsNullOrEmpty(returnUrl))  
  11.                     return Redirect(returnUrl);  
  12.                 return RedirectToAction(“Index”, “Home”);  
  13.             }  
  14.             return View(model);  
  15.         }  

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            var query = HttpUtility.ParseQueryString(Request.UrlReferrer.Query);
    

                if (model.UserName == “ojlovecd@csdn.net” && model.Password == “123456”)
                {
                    FormsAuthentication.SetAuthCookie(“ojlovecd@csdn.net|1983-10-22|oujian”, false);
                    if (!string.IsNullOrEmpty(returnUrl))
                        return Redirect(returnUrl);
                    return RedirectToAction(“Index”, “Home”);
                }
                return View(model);

        }
    

LogOff方法修改如下:

 

 

[csharp] view
plain
copyprint?

  1.         public ActionResult LogOff()  
  2.         {  
  3.             FormsAuthentication.SignOut();  
  4.             ViewData[“AddressesExpected”] = SingleSignOnManager.SignOut().Distinct().ToArray();  
  5.             return View(“Login”);  
  6.         }  

        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
    

                ViewData[“AddressesExpected”] = SingleSignOnManager.SignOut().Distinct().ToArray();
                return View(“Login”);

        }
    

开辟/Views/Account/Login.cshtml,添加以下代码:

 

 

[html] view
plain
copyprint?

  1. @{  
  2.     ViewBag.Title = “登录”;  
  3.     var addressesExpected = ViewData[“AddressesExpected”] as string[];  
  4.     if (addressesExpected != null)  
  5.     {  
  6.         foreach (var address in addressesExpected)  
  7.         {  
  8.     <img src=”@(address)?wa=wsignoutcleanup1.0″ style=”display:none;” />  
  9.         }  
  10.     }  
  11.   
  12. }  

    @{

    ViewBag.Title = "登录";
    var addressesExpected = ViewData["AddressesExpected"] as string[];
    if (addressesExpected != null)
    {
        foreach (var address in addressesExpected)
        {
    <img src="@(address)?wa=wsignoutcleanup1.0" style="display:none;" />
        }
    }
    

    }

OK,至此STS也已经形成了。把SiteA和STS都配备到IIS上,然后打开C:\Windows\System32\Drivers\etc\hosts文件,添加多少个站点:

 

[plain] view
plain
copyprint?

  1. 127.0.0.1   www.sitea.com  
  2. 127.0.0.1   www.siteb.com  
  3. 127.0.0.1   www.sitec.com  
  4. 127.0.0.1   www.sited.com  
  5. 127.0.0.1   www.sts.com  

    127.0.0.1 www.sitea.com
    127.0.0.1 www.siteb.com
    127.0.0.1 www.sitec.com
    127.0.0.1 www.sited.com
    127.0.0.1 www.sts.com

 

 

好了,在浏览器输入www.sitea.com,看看哪些,它立时跳转到了www.sts.com的登录页面,输入ojlovecd@csdn.net,密码12345陆,明确,登录成功,跳回到了www.sitea.com,并展现出了用户名和Email:
起名 6

点击退出,将撤销当前用户,并跳转到登录页。

 

  请珍重笔者劳动成果,转载请标明原作链接:

三、创立此外福特ExplorerP

OK,站点A解决了,那其余站点怎么着呢?现在只是最简便的记名退出职能而已,说好的单点登录呢?
别急,接下去就相继落成。 新建基于.NET
Framework肆.5的MVC四程序,添加Microsoft.IdentityModel引用。修改web.config,configSections里添加如下节点:

[html] view
plain
copyprint?

  1. <section name=”microsoft.identityModel” type=”Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ />  

    <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    

Compilation里扩大Microsoft.IdentityModel的主次集:

[html] view
plain
copyprint?

  1. <compilation debug=”true” targetFramework=”4.5″ >  
  2.   <assemblies>  
  3.     <add assembly=”Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>  
  4.   </assemblies>  
  5. </compilation>  

    <compilation debug="true" targetFramework="4.5" >
      <assemblies>
        <add assembly="Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      </assemblies>
    </compilation>
    

身份验证改为None,添加authorization节点,禁止匿名用户访问:

[html] view
plain
copyprint?

  1. <authentication mode=”None”>  
  2. </authentication>  
  3. <authorization>  
  4.   <deny users=”?” />  
  5. </authorization>  

    <authentication mode="None">
    </authentication>
    <authorization>
      <deny users="?" />
    </authorization>
    

增进八个httpModules:     

[html] view
plain
copyprint?

  1. <httpModules>  
  2.       <add name=”WSFederationAuthenticationModule” type=”Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ />  
  3.       <add name=”SessionAuthenticationModule” type=”Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ />  
  4.       <add name=”ClaimsAuthorizationModule” type=”Microsoft.IdentityModel.Web.ClaimsAuthorizationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ />  
  5.     </httpModules>  
  6. system.webServer里添加以下三个modules:  
  7.     <modules >  
  8.       <add name=”WSFederationAuthenticationModule” type=”Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ preCondition=”managedHandler” />  
  9.       <add name=”SessionAuthenticationModule” type=”Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ preCondition=”managedHandler” />  
  10.       <add name=”ClaimsAuthorizationModule” type=”Microsoft.IdentityModel.Web.ClaimsAuthorizationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ preCondition=”managedHandler” />  
  11.     </modules>  

      <add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add name="ClaimsAuthorizationModule" type="Microsoft.IdentityModel.Web.ClaimsAuthorizationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpModules>
    

    system.webServer里添加以下五个modules:

    <modules >
      <add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
      <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
      <add name="ClaimsAuthorizationModule" type="Microsoft.IdentityModel.Web.ClaimsAuthorizationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
    </modules>
    

最终增添microsoft.identityModel节点:  

[html] view
plain
copyprint?

  1. <microsoft.identityModel>  
  2.    <service>  
  3.      <audienceUris mode=”Always”>  
  4.        <add value=”http://www.siteb.com” />  
  5.      </audienceUris>  
  6.      <federatedAuthentication>  
  7.        <wsFederation passiveRedirectEnabled=”true” issuer=”http://www.sts.com” realm=”http://www.siteb.com” reply=”http://www.siteb.com”  requireHttps=”false” />  
  8.        <cookieHandler requireSsl=”false” />  
  9.      </federatedAuthentication>  
  10.      <issuerNameRegistry type=”Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″>  
  11.        <trustedIssuers>  
  12.          <add thumbprint=”FD1425A2F30937786F46E52E43B01AFD54E5D64D” name=”http://www.sts.com” />  
  13.        </trustedIssuers>  
  14.      </issuerNameRegistry>  
  15.    </service>  
  16.  </microsoft.identityModel>  

    <service>
      <audienceUris mode="Always">
        <add value="http://www.siteb.com" />
      </audienceUris>
      <federatedAuthentication>
        <wsFederation passiveRedirectEnabled="true" issuer="http://www.sts.com" realm="http://www.siteb.com" reply="http://www.siteb.com"  requireHttps="false" />
        <cookieHandler requireSsl="false" />
      </federatedAuthentication>
      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <trustedIssuers>
          <add thumbprint="FD1425A2F30937786F46E52E43B01AFD54E5D64D" name="http://www.sts.com" />
        </trustedIssuers>
      </issuerNameRegistry>
    </service>
    

以上配置跟SIteA大约,只是WIF叁.伍和四.⑤的分别而已,在那边就不赘述了,要拿走详细音信,请参考微软官方网址。
打开/Views/Home/Index.cshtml,将代码修改如下,在SiteB里大家呈现Email和生辰:

[html] view
plain
copyprint?

  1. @using Microsoft.IdentityModel.Claims  
  2. @{  
  3.     ViewBag.Title = “SiteB主页”;  
  4.     ClaimsIdentity ci = User.Identity as ClaimsIdentity;  
  5.     if(ci!=null)  
  6.     {  
  7.         <h2>@ci.Claims.SingleOrDefault(c=>c.ClaimType == ClaimTypes.Email).Value</h2>  
  8.         <h2>@ci.Claims.SingleOrDefault(c=>c.ClaimType == ClaimTypes.DateOfBirth).Value</h2>  
  9.     }  
  10. }  
  11.   
  12.   
  13. <a href=”http://www.sts.com/Account/LogOff"&gt;退出&lt;/a&gt;  

    @using Microsoft.IdentityModel.Claims
    @{

    ViewBag.Title = "SiteB主页";
    ClaimsIdentity ci = User.Identity as ClaimsIdentity;
    if(ci!=null)
    {
        <h2>@ci.Claims.SingleOrDefault(c=>c.ClaimType == ClaimTypes.Email).Value</h2>
        <h2>@ci.Claims.SingleOrDefault(c=>c.ClaimType == ClaimTypes.DateOfBirth).Value</h2>
    }
    

    }

<a href="http://www.sts.com/Account/LogOff">退出</a>

OK,布署到IIS上,然后运转,页面跳转到了sts的报到页面,输入用户名和密码,跳转,哎哎小编去,怎么报错了:
起名 7
由来是从sts重临来的数额里有<>这种标签,于是asp.net认为那是有危险的,于是抛出了老大,那一个相当大家估摸在此在此以前也遇上过,最简便易行无情的办法正是把验证请求的布局改为false,但那里自身不建议那样干,
为此,大家特地用1个类来处理这种意况。
在SiteB目录下新建三个文书夹名叫Services,然后添加多少个类,名称叫SampleRequestValidator:
  

[csharp] view
plain
copyprint?

  1. /// <summary>  
  2.   /// This SampleRequestValidator validates the wresult parameter of the  
  3.   /// WS-Federation passive protocol by checking for a SignInResponse message  
  4.   /// in the form post. The SignInResponse message contents are verified later by  
  5.   /// the WSFederationPassiveAuthenticationModule or the WIF signin controls.  
  6.   /// </summary>  
  7.   
  8.   
  9.   public class SampleRequestValidator : RequestValidator  
  10.   {  
  11.       protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)  
  12.       {  
  13.           validationFailureIndex = 0;  
  14.   
  15.   
  16.           if (requestValidationSource == RequestValidationSource.Form && collectionKey.Equals(WSFederationConstants.Parameters.Result, StringComparison.Ordinal))  
  17.           {  
  18.                   return true;  
  19.           }  
  20.   
  21.   
  22.           return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);  
  23.       }  
  24.   
  25.   
  26.   }  

    ///

    /// This SampleRequestValidator validates the wresult parameter of the
    /// WS-Federation passive protocol by checking for a SignInResponse message
    /// in the form post. The SignInResponse message contents are verified later by
    /// the WSFederationPassiveAuthenticationModule or the WIF signin controls.
    /// </summary>
    
    public class SampleRequestValidator : RequestValidator
    {
        protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
        {
            validationFailureIndex = 0;


            if (requestValidationSource == RequestValidationSource.Form && collectionKey.Equals(WSFederationConstants.Parameters.Result, StringComparison.Ordinal))
            {
                    return true;
            }


            return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
        }


    }

接下来在web.config里进入这些类的安插:

[html] view
plain
copyprint?

  1. <httpRuntime targetFramework=”4.5″ requestValidationType=”SiteC.Services.SampleRequestValidator” />  

    <httpRuntime targetFramework="4.5" requestValidationType="SiteC.Services.SampleRequestValidator" />
    

再度运转程序,相当周到:
起名 8
那时候再打开SIteA,发现也早已处在了登录情况,那时候在SiteA点击退出,跳转到了登录页,再看看那时候的SiteB呢,刷新SiteB首页,发现也跳转到了登录页,表明在SiteA的退出操作对SiteB也起了功效,确实是单点登录了!
SiteC和SiteD的配置与SiteB类似,这里小编就不另行了,留给大家自个儿练习一下,等全体的品类都安顿好之后,在任意站点登录,发现其余站点也是登录状态;在四意站点退出,发现别的站点也早就淡出。利用WIF,单点登录变的这样容易~~

  http://www.cnblogs.com/dolphin0520/p/3811445.html

壹.内类型基础

  在Java中,可以将三个类定义在另多个类里面大概三个办法里面,那样的类称为个中类。广泛意义上的内部类一般的话包含那多种:成员内部类、局地内部类、匿名内部类和静态内部类。上面就先来打探一下那三种内部类的用法。

  一.成员内部类

  成员内部类是最家常的里边类,它的概念为位于另一个类的内部,形如下边包车型地铁款型:

class Circle {
    double radius = 0;

    public Circle(double radius) {
        this.radius = radius;
    }

    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println("drawshape");
        }
    }
}

  那样看起来,类Draw像是类Circle的一个分子,Circle称为外部类。成员内部类能够无偿访问外部类的兼具成员属性和分子方法(包蕴private成员和静态成员)。

class Circle {
    private double radius = 0;
    public static int count =1;
    public Circle(double radius) {
        this.radius = radius;
    }

    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
            System.out.println(count);   //外部类的静态成员
        }
    }
}

  可是要留心的是,当成员内部类具有和外部类同名的分子变量只怕措施时,会产生隐藏现象,即暗中同意情形下访问的是成员内部类的分子。倘若要访问外部类的同名成员,须求以上面包车型客车款式展开访问:

外部类.this.成员变量
外部类.this.成员方法

  即使成员内部类能够无偿地拜会外部类的分子,而外部类想拜会成员内部类的积极分子却不是那样随便了。在表面类中壹经要拜访成员内部类的分子,必须先创设两个分子内部类的靶子,再经过指向这些指标的引用来拜访:

class Circle {
    private double radius = 0;

    public Circle(double radius) {
        this.radius = radius;
        getDrawInstance().drawSahpe();   //必须先创建成员内部类的对象,再进行访问
    }

    private Draw getDrawInstance() {
        return new Draw();
    }

    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
        }
    }
}

  成员内部类是隶属外部类而存在的,也正是说,假设要创立成员内部类的靶子,前提是必须存在贰个表面类的对象。创造成员内部类对象的貌似方法如下:

public class Test {
    public static void main(String[] args)  {
        //第一种方式:
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();  //必须通过Outter对象来创建

        //第二种方式:
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}

class Outter {
    private Inner inner = null;
    public Outter() {

    }

    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }

    class Inner {
        public Inner() {

        }
    }
}

  内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上边的事例,假如成员内部类Inner用private修饰,则只可以在外部类的里边访问,若是用public修饰,则别的地点都能访问;假诺用protected修饰,则只万幸同一个包下或然三番五次外部类的场合下访问;如若是暗许访问权限,则只万幸同一个包下访问。这或多或少和外部类有某个不一致,外部类只可以被public和包访问两种权限修饰。小编个人是这么清楚的,由于成员内部类看起来像是外项指标1个分子,所以能够像类的分子平等享有多样权力修饰。

  二.局地内部类

  局地内部类是概念在叁个格局照旧一个成效域里面的类,它和成员内部类的分别在于有的内部类的走访仅限于方法内还是该功用域内。

class People{
    public People() {

    }
}

class Man{
    public Man(){

    }

    public People getWoman(){
        class Woman extends People{   //局部内部类
            int age =0;
        }
        return new Woman();
    }
}

  注意,局地内部类就像方法里面包车型地铁二个片段变量一样,是不能够有public、protected、private以及static修饰符的。

  3.匿名内部类

  匿名内部类应该是日常我们编辑代码时用得最多的,在编写事件监听的代码时选用匿名内部类不但有利于,而且使代码尤其便于保险。下边那段代码是1段Android事件监听代码:

scan_bt.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        });

        history_bt.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        });

  那段代码为三个按钮设置监听器,那之中就选取了匿名内部类。那段代码中的:

new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        }

  便是匿名内部类的使用。代码中须要给按钮设置监听器对象,使用匿名内部类可以在落到实处父类也许接口中的方法情况下同时爆发二个一点钟情的对象,但是前提是其1父类大概接口必须先存在才能这么使用。当然像上边那种写法也是能够的,跟上边使用匿名内部类达到效果壹样。

private void setListener()
{
    scan_bt.setOnClickListener(new Listener1());        
    history_bt.setOnClickListener(new Listener2());
}

class Listener1 implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub

    }
}

class Listener2 implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub

    }
}

  那种写法即使能落成同等的效率,不过既冗长又难以有限支撑,所以壹般选择匿名内部类的办法来编排事件监听代码。同样的,匿名内部类也是不能够有访问修饰符和static修饰符的。

  匿名内部类是唯1一种没有构造器的类。正因为其没有构造器,所以匿名内部类的应用范围10分有限,当先5玖%匿名内部类用于接口回调。匿名内部类在编写翻译的时候由系统活动起名字为Outter$壹.class。一般的话,匿名内部类用于后续别的类恐怕完成接口,并不需求扩充额外的章程,只是对继续方法的落实或是重写。

  四.静态内部类

  静态内部类也是概念在另2个类里面包车型大巴类,只可是在类的前边多了四个首要字static。静态内部类是不须要借助于表面类的,那点和类的静态成员属性有点类似,并且它不能够选用外部类的非static成员变量只怕措施,这一点很好明白,因为在未有外部类的对象的状态下,能够创造静态内部类的目的,假若同意访问外部类的非static成员就会发生顶牛,因为表面类的非static成员必须依附于实际的目的。

public class Test {
    public static void main(String[] args)  {
        Outter.Inner inner = new Outter.Inner();
    }
}

class Outter {
    public Outter() {

    }

    static class Inner {
        public Inner() {

        }
    }
}

  起名 9

2.深远驾驭当中类

  一.为啥成员内部类能够无条件访问外部类的成员?

  以前,我们已经探究过了成员内部类能够无偿访问外部类的成员,那现实究竟是何许完成的啊?下面通过反编译字节码文件看看终究。事实上,编写翻译器在开始展览编写翻译的时候,会将成员内部类单独编译成3个字节码文件,下边是Outter.java的代码:

public class Outter {
    private Inner inner = null;
    public Outter() {

    }

    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }

    protected class Inner {
        public Inner() {

        }
    }
}

  编译之后,出现了多少个字节码文件:

起名 10

  反编写翻译Outter$Inner.class文件获得上面消息:

E:\Workspace\Test\bin\com\cxh\test2>javap -v Outter$Inner
Compiled from "Outter.java"
public class com.cxh.test2.Outter$Inner extends java.lang.Object
  SourceFile: "Outter.java"
  InnerClass:
   #24= #1 of #22; //Inner=class com/cxh/test2/Outter$Inner of class com/cxh/tes
t2/Outter
  minor version: 0
  major version: 50
  Constant pool:
const #1 = class        #2;     //  com/cxh/test2/Outter$Inner
const #2 = Asciz        com/cxh/test2/Outter$Inner;
const #3 = class        #4;     //  java/lang/Object
const #4 = Asciz        java/lang/Object;
const #5 = Asciz        this$0;
const #6 = Asciz        Lcom/cxh/test2/Outter;;
const #7 = Asciz        <init>;
const #8 = Asciz        (Lcom/cxh/test2/Outter;)V;
const #9 = Asciz        Code;
const #10 = Field       #1.#11; //  com/cxh/test2/Outter$Inner.this$0:Lcom/cxh/t
est2/Outter;
const #11 = NameAndType #5:#6;//  this$0:Lcom/cxh/test2/Outter;
const #12 = Method      #3.#13; //  java/lang/Object."<init>":()V
const #13 = NameAndType #7:#14;//  "<init>":()V
const #14 = Asciz       ()V;
const #15 = Asciz       LineNumberTable;
const #16 = Asciz       LocalVariableTable;
const #17 = Asciz       this;
const #18 = Asciz       Lcom/cxh/test2/Outter$Inner;;
const #19 = Asciz       SourceFile;
const #20 = Asciz       Outter.java;
const #21 = Asciz       InnerClasses;
const #22 = class       #23;    //  com/cxh/test2/Outter
const #23 = Asciz       com/cxh/test2/Outter;
const #24 = Asciz       Inner;

{
final com.cxh.test2.Outter this$0;

public com.cxh.test2.Outter$Inner(com.cxh.test2.Outter);
  Code:
   Stack=2, Locals=2, Args_size=2
   0:   aload_0
   1:   aload_1
   2:   putfield        #10; //Field this$0:Lcom/cxh/test2/Outter;
   5:   aload_0
   6:   invokespecial   #12; //Method java/lang/Object."<init>":()V
   9:   return
  LineNumberTable:
   line 16: 0
   line 18: 9

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      10      0    this       Lcom/cxh/test2/Outter$Inner;


}

  第二一行到3五行是常量池的始末,下边逐一第1八行的内容:

final com.cxh.test2.Outter this$0;

  这行是1个针对性外部类对象的指针,看到此间可能咱们出现转机了。也正是说编写翻译器会暗中同意为成员内部类添加了1个对准外部类对象的引用,那么这么些引用是什么样赋初值的吧?上边接着看当中类的构造器:

public com.cxh.test2.Outter$Inner(com.cxh.test2.Outter);

  从此处能够见到,固然大家在概念的其中类的构造器是无参构造器,编写翻译器照旧会默许添加2个参数,该参数的品类为指向外部类对象的二个引用,所以成员内部类中的Outter
this&0
指针便指向了表面类对象,因此能够在成员内部类中任意走访外部类的分子。从此间也直接表达了成员内部类是凭借于外部类的,假诺未有开创外部类的指标,则无从对Outter
this&0引用举办早先化赋值,也就不能创立成员内部类的靶子了。

  2.怎么有个别内部类和匿名内部类只可以访问壹些final变量?

  想必那个题材也早就干扰过很多少人,在研商那么些标题之前,先看上面这段代码:

public class Test {
    public static void main(String[] args)  {

    }

    public void test(final int b) {
        final int a = 10;
        new Thread(){
            public void run() {
                System.out.println(a);
                System.out.println(b);
            };
        }.start();
    }
}

  那段代码会被编写翻译成七个class文件:Test.class和Test$壹.class。暗许境况下,编译器会为匿名内部类和部分内部类起名称叫Outter$x.class(x为正整数)。

  起名 11

  依照上航海用体育场合能够,test方法中的匿名内部类的名字被起为 Test$1。

  上段代码中,假若把变量a和b前边的任一个final去掉,那段代码都编译可是。大家先思虑那样2个题材:

  当test方法执行达成之后,变量a的生命周期就过逝了,而那时候Thread对象的生命周期一点都不小概还不曾为止,那么在Thread的run方法中继续走访变量a就成为不容许了,不过又要兑现如此的意义,怎么做吧?Java选取了
复制 
的手段来消除那个题材。将那段代码的字节码反编写翻译能够拿走下边包车型大巴始末:

起名 12

  我们见到在run方法中有一条指令:

bipush 10

  那条指令表示将操作数10压栈,表示使用的是三个地点局地变量。那些进度是在编写翻译时期由编译器暗中认可进行,假若那几个变量的值在编写翻译时期能够规定,则编写翻译器暗中认可会在匿名内部类(局地内部类)的常量池中添加1个内容万分的字面量或间接将相应的字节码嵌入到执行字节码中。那样一来,匿名内部类使用的变量是另三个有个别变量,只可是值和情势中有个别变量的值十三分,因而和方法中的局地变量完全独立开。

  上边再看一个事例:

public class Test {
    public static void main(String[] args)  {

    }

    public void test(final int a) {
        new Thread(){
            public void run() {
                System.out.println(a);
            };
        }.start();
    }
}

  反编写翻译获得:

起名 13

  大家见到匿名内部类Test$一的构造器含有三个参数,四个是指向外部类对象的引用,贰个是int型变量,很醒目,那里是将变量test方法中的形参a以参数的款式传进来对匿名内部类中的拷贝(变量a的正片)举办赋值开头化。

  也就说假若有的变量的值在编写翻译时期就足以分明,则一直在匿名内部里面创设二个拷贝。要是部分变量的值不能在编写翻译时期确定,则经过构造器传参的办法来对拷贝进行伊始化赋值。

  从地点能够见见,在run方法中访问的变量a根本就不是test方法中的局地变量a。那样一来就缓解了前边所说的
生命周期不等同的题材。可是新的题材又来了,既然在run方法中走访的变量a和test方法中的变量a不是同二个变量,当在run方法中改变变量a的值的话,会油然则生什么情状?

  对,会导致数据不一致性,那样就达不到原来的意向和要求。为了解决这几个题材,java编写翻译器就限制必须将变量a限制为final变量,不一致意对变量a进行更改(对于引用类型的变量,是不允许指向新的目的),那样数据不一致性的标题就足以解决了。

  到此地,想必大家应该知道怎么
方法中的局地变量和形参都必须用final进行限制了。

  3.静态内部类有尤其的地点呢?

  在此以前面能够知道,静态内部类是不借助于于表面类的,也就说能够在不创立外部类对象的气象下开创内部类的指标。其余,静态内部类是不富有指向外部类对象的引用的,那几个读者能够协调尝试反编写翻译class文件看一下就清楚了,是尚未Outter
this&0引用的。

三.内部类的应用处境和好处

  为何在Java中须求中间类?计算一下生死攸关有以下四点:

  1.种种内部类都能独立的持续二个接口的落到实处,所以无论是外部类是还是不是早已延续了某些(接口的)完毕,对于内部类都不曾影响。内部类使得多一连的消除方案变得完全,

  贰.有利将存在一定逻辑关系的类组织在1起,又能够对外场隐藏。

  三.造福编写事件驱动程序

  四.便利编写线程代码

  个人觉得第叁点是最重点的来由之壹,内部类的存在使得Java的多继承机制变得进一步完美。

肆.常见的与个中类相关的笔试面试题

 壹.基于注释填写(1),(二),(③)处的代码

public class Test{
    public static void main(String[] args){
           // 初始化Bean1
           (1)
           bean1.I++;
           // 初始化Bean2
           (2)
           bean2.J++;
           //初始化Bean3
           (3)
           bean3.k++;
    }
    class Bean1{
           public int I = 0;
    }

    static class Bean2{
           public int J = 0;
    }
}

class Bean{
    class Bean3{
           public int k = 0;
    }
}

  从前边可见,对于成员内部类,必须头阵生外部类的实例化对象,才能发出内部类的实例化对象。而静态内部类不用爆发外部类的实例化对象即可发生内部类的实例化对象。

  创造静态内部类对象的貌似方式为: 
外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()

  制造成员内部类对象的相似格局为: 
外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()

  因而,(壹),(2),(三)处的代码分别为:

起名 14起名 15

Test test = new Test();    

  Test.Bean1 bean1 = test.new Bean1();   

View Code

 

起名 16起名 17

Test.Bean2 b2 = new Test.Bean2();    

View Code

 

起名 18起名 19

Bean bean = new Bean();     

Bean.Bean3 bean3 =  bean.new Bean3();   

View Code

二.下边那段代码的出口结果是怎样?

public class Test {
    public static void main(String[] args)  {
        Outter outter = new Outter();
        outter.new Inner().print();
    }
}


class Outter
{
    private int a = 1;
    class Inner {
        private int a = 2;
        public void print() {
            int a = 3;
            System.out.println("局部变量:" + a);
            System.out.println("内部类变量:" + this.a);
            System.out.println("外部类变量:" + Outter.this.a);
        }
    }
}

起名 20起名 21

3
2
1

View Code

 

  最后补充某个学问:关于成员内部类的接二连三难题。一般的话,内部类是很少用来作为三番五次用的。但是当用来再而三的话,要留意两点:

  壹)成员内部类的引用格局必须为 Outter.Inner.

  2)构造器中务必有针对性外部类对象的引用,并透过那么些引用调用super()。那段代码摘自《Java编制程序思想》

class WithInner {
    class Inner{

    }
}
class InheritInner extends WithInner.Inner { 

    // InheritInner() 是不能通过编译的,一定要加上形参 
    InheritInner(WithInner wi) { 
        wi.super(); //必须有这句调用
    } 

    public static void main(String[] args) { 
        WithInner wi = new WithInner(); 
        InheritInner obj = new InheritInner(wi); 
    } 
} 

 

 参考资料:

  《java编制程序思想》

  http://www.cnblogs.com/chenssy/p/3388487.html

  http://blog.csdn.net/zhangjg_blog/article/details/20000769

  http://blog.csdn.net/zhangjg_blog/article/details/19996629

  http://blog.csdn.net/zhaoqianjava/article/details/6849812

  http://www.cnblogs.com/nerxious/archive/2013/01/24/2875649.html

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图