Form验证

代码写 N 久了,总想写得别的。这不,上头说在整合两个项目,做成单一登录(Single Sign On),也有人称之为“单点登录”。查阅相关文档后,终于实现了,现在把它拿出来与大家一起分享。或许大家会问:“这与标题不符呀?”别急,在下笔之前,我脑子里想到了我刚使用 Form 认证时遇到的一些问题,以及使用过程用到的一些技巧(实乃投机取巧是也 ^_^ )。偶打初中那时,语文水平就不怎么滴,考试常常作文写不出来,所以写作水平有限,还请大家海量。对了,本人不仅写作水平有限,编程能力也不是很好,此文供大家学习交流之用,欢迎广大劳苦群众拎着鸡蛋、捧着鲜花前来评论。转载请注明原创作者乃寒羽枫是也,不甚感激!

废话也说的差不多了,言归正传, ASP.NET 的安全认证,共有“Windows”“Form”“Passport”“None”四种验证模式。“Windows”与“None”没有起到保护的作用,不推荐使用;“Passport”我又没用过,唉……所以我只好讲讲“Form”认证了。我打算分三部分:

第一部分——怎样实现From 认证;

第二部分—— Form 认证的实战运用;

第三部分——实现单点登录(Single Sign On)

第一部分如何运用 Form 表单认证

一、新建一个测试项目

为了更好说明,有必要新建一个测试项目(暂且为“FormTest”吧),包含三张页面足矣(Default.aspx、Login.aspx、UserInfo.aspx)。啥?有人不会新建项目,不会新增页面?你问我咋办?我看这么办好了:拖出去,打回原藉,从幼儿园学起……

二、修改 Web.config

1、 双击项目中的Web.config(不会的、找不到的打 PP)

2、 找到下列文字<authenticationmode="Windows"/> 把它改成:

<authenticationmode="Forms">

<formslogi nUrl="Login.aspx"name=".ASPXAUTH"></forms>

</authentication>

3、 找到<authorization><allowusers="*"/></authorization>换成

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

这里没什么好说的,只要拷贝过去就行。虽说如此,但还是有人会弄错,如下:

<authenticationmode="Forms">

<formslogin Url="Login.aspx"name=".APSX"></forms>

<denyusers="?"></deny>

</authentication>

若要问是谁把<denyusers="?"></deny>放入<authentication>中的,我会很荣幸地告诉你,那是 N 年前的我:<authentication>与<authorization>都是以auth字母开头又都是以ation结尾,何其相似;英文单词背不下来的我以为他们是一伙的……

三、编写 .cs 代码——登录与退出

1、 登录代码:

a、 书本上介绍的

private void Btn_Login_Click(object sender, System.EventArgs e)

         {

if(this.Txt_UserName.Text=="Admin" && this.Txt_Password.Text=="123456")

              {

System.Web.Security.FormsAuthentication.RedirectFromLoginPage(this.Txt_UserName.Text,false);

      }

}

b、 偶找了 N 久才找到的

private void Btn_Login_Click(object sender, System.EventArgs e)

         {

if(this.Txt_UserName.Text=="Admin" && this.Txt_Password.Text=="123456")

              {

System.Web.Security.FormsAuthentication.SetAuthCookie(this.Txt_UserName.Text,false);

     Response.Redirect("Default.aspx");

     }

}

以上两种都可发放验证后的Cookie,即通过验证,区别:

方法 a) 指验证后返回请求页面,俗称“从哪来就打哪去”。比如:用户没登录前直接在 IE 地址栏输入http://localhost/FormTest/UserInfo.aspx,那么该用户将看到的是Login.aspx?ReturnUrl=UserInfo.aspx,输入用户名与密码登录成功后,系统将根据“ReturnUrl”的值,返回相应的页面

方法 b) 则是分两步走:通过验证后就直接发放Cookie,跳转页面将由程序员自行指定,此方法多用于Default.aspx 使用框架结构的系统。

2、 退出代码:

private void Btn_LogOut_Click(object sender, System.EventArgs e)

     {

System.Web.Security.FormsAuthentication.SignOut();

}

四、如何判断验证与否及获取验证后的用户信息

有的时候,在同一张页面需要判断用户是否已经登录,然后再呈现不同的布局。有人喜欢用Session来判断,我不反对此类做法,在此我只是想告诉大家还有一种方法,且看下面代码:

if(User.Identity.IsAuthenticated)

         {

//你已通过验证,知道该怎么做了吧?

}

User.Identity还有两个属性AuthenticationType(验证类型)与Name(用户名称),大家要注意的是Name属性,此处的User.Identity.Name将得到,验证通过(RedirectFromLoginPage或SetAuthCookie)时,我们带入的第一个参数this.Txt_UserName.Text 。这个参数很重要,关系到种种……种种的情况,何出此言,且听下回分解……

第二部分 Form 认证的实战运用

话说上回,简单地说了一下 Form 表单认证的用法。或许大家觉得太简单,对那些大内高手来说应该是“洒洒水啦”“小 Kiss 啦(小意思)”。今天咱们来点的花样吧:古有六扇门,拒收叶孤城;东门不刮风,吹雪姓西门;缎带作凭证,决战紫禁城。

五、Web.config 的作用范围

新建项目时, VS.Net 会在项目根目录建立一个内容固定的 Web.config。除了在项目根目录,你还可以在任一目录下建立 Web.config ,条件就是应用程序级别的节点只能在根目录的 Web.config 中出现。至于哪些是应用程序级别节点呢,这个问题嘛,其实我也不太清楚,呵呵。电脑不是我发明的,微软不是我创建的,C# 更不是我说了算的,神仙也有不知道的,所以我不晓得是正常的。话虽如此,只要它不报错,那就是对的。

关于 Web.config 设置的作用范围,记住以下两点:

1、  Web.config 的设置将作用于所在目录的所有文件及其子目录下的所有东东(继承:子随父姓)

2、 子目录下的 Web.config 设置将覆盖由父目录继承下来的设置(覆盖:县官不如现管)

给大家提个问题:有没有比根目录Web.config 的作用范围还大的配置文件呢?看完第三部分便知分晓。

六、学会拒绝与巧用允许

回到我们在第一回合新建的测试项目“FormTest”, 既然要进行验证,按国际惯例,就得有用户名与密码。那,这些用户是管理员自己在数据库建好呢,还是用户注册、管理员审核好呢。只要不是一般的笨蛋,都知道选择后者。你们还别说,我公司还真有个别项目是管理员连到数据库去建帐号的,属于比较特殊的笨蛋,咱们不学他也罢,还是老老实实添加两个页面吧——注册页面(Register.aspx)与审核页面(Auditing.aspx)。

问题终于就要浮出水面啦,当你做好Register.aspx时,想访问它的时候突然觉得不对劲,怎么又回到了登录页面?你仔细瞧瞧网址,是不是成了:Login.aspx?ReturnUrl=Register.aspx。怎么办,用户就是因为没有帐号才去访问注册页面的呀?(这句纯属废话,有帐号谁还跑去注册。)我时常对我的同事说:“办法是人想出来滴!!”

1、新建一个目录Public,用于存放一些公用的文件,如万年历、脚本呀……

2、在“解决方案资源管理器”中右击点击目录Public,新增一个Web.config

3、把上述Web.config的内容统统删除,仅留以下即可:

<?xmlversion="1.0"encoding="utf-8"?>

<configuration>

<system.web>

<authorization><allow users="*"/></authorization>

</system.web>

</configuration>

终于切入正题了,不容易呀。根据“覆盖”原则,我们知道上述Web.config将替代根目录Web.config中的<authorization>节点设置,即:

<allowusers="*"/>替换<denyusers="?"></deny>

注解:“allow”允许的意思;“*”表示所有用户;

“deny”拒绝的意思;“?”表示匿名用户;

因此,处于Public目录下的文件,允许所有人浏览,包括未验证的用户。把Register.aspx拖进来吧,再也不会有人阻止你浏览啦。

除了注册页面,我们还提到一个审核页面(Auditing.aspx),审核权限一般都在管理员或主管手里,并不想让其他人浏览此页面(真理往往掌握在少数人的手里,这也是没法子的事),怎么办?“办法是人想出来滴”呵呵……新建一个管理员的目录ManageSys,在此目录下再新增一个Web.config。内容如下:

<?xmlversion="1.0"encoding="utf-8"?>

<configuration>

<system.web>

<authorization>

<allow users="Admin"/>

<deny users="*"/>

</authorization>

</system.web>

</configuration>

现在的问题就是怎么才能知道谁是“Admin”呢,这个问题就有点象“我的鞋底有个洞”——天不知地知,你不知我知。闲话少说(要是有稿费多好,我就有多写几个字的动力,唉……),大家还记得我在第一部分的结尾吗?什么,忘啦!罚你回去看一百遍,记住了再回来。站住,回来!一想到你的记性,我就不放心,第一部分的浏览网址是http://blog.csdn.net/cityhunter172/archive/2005/11/06/524043.aspx,回到此处的网址是http://blog.csdn.net/cityhunter172/archive/2005/11/13/528463.aspx

好了,不管那些记不好的家伙了,大伙继续往下看。

System.Web.Security.FormsAuthentication.SetAuthCookie(this.Txt_UserName.Text,false);//通过验证,发放Cookie

之前我曾强调,要注意,第一个参数很重要,重要到什么程度?说到这,恐怕地球人都知道了——它就是allow与deny的依据。假如此处用户填写的是“Admin”即this.Txt_UserName.Text="Admin";那么进入系统后,他就能访问ManageSys目录下的网页了,其它闲杂人等一律拒之门外。

为巩固上述内容,给大伙留个课外作业:此项目有两部门使用,其中每个部门分别都有些特定的页面仅供本部门用户浏览使用,请问该如何使用Web.config达到效果?同样,答案在第三部分揭晓

七、分散与集中

乍看之下,就象是马克思列宁主义、***思想、***理论中的辩证关系,大伙放心,偶是学理科的,只明白“高举程序员的伟大旗帜,以编写代码为中心”。停……

到目前为此,我们的测试项目“FormTest”已经拥有两个目录三个Web.config,伴随用户需求的多样化,Web.config也会越来越多,比如常用的文件上传功能等等。众多的Web.config分布在不同的目录里面,维护起来肯定比较烦人。能不能集中起来管理呢,应该咋办哩?“办法是……”哟,有人先说出来啦。不错,“办法的确是人想出来滴”,我不说,你是不是只有在一边凉伴?开玩笑的,为了让更多的人记住这句话,我打算告诉你集中管理的办法。

要想集中管理,不得不用到<location>节点与path属性。在本项目中,我们将目录Public与ManageSys下的设置放在根目录下的Web.config里面,如下:

<?xml version="1.0" encoding="utf-8"?>

<configuration>

<location path="Public">

<system.web>

<authorization>

<allow users="*"/>

</authorization>

</system.web>

</location>

<location path="ManageSys">

<system.web>

<authorization>

<allow users="Admin"/>

<deny users="*"/>

</authorization>

</system.web>

</location>

<system.web>

<!--这里放置原来根目录Web.config的内容,就不列出来了-->

</system.web>

</configuration>

需要提醒的是

1、<location>节点的位置是在<configuration>的一个子节点,它与原有的<system.web>属于并列关系

2、<location>节点只需要放入对应子目录Web.config中的<system.web>的节点内容

八、额外的保护

第二部分就要结束了,现在时间已是凌晨4点50分,我容易嘛我。认证的目的就是为了防止他人非法浏览页面,或未经许可使用某些功能。当然,世上没有绝对的安全,如今MD5加密都被我们国人给破解了,就是最好的例证。

细心的人可能早就发现ASP.NET的安全认证只针对.aspx、.ascx……等ASP.NET文件起作用,而对普通页面与文件却“视而不见”,如.htm、.js、.jpg等。通过以下步骤你就可以保护你想保护的文件类型。

1、打开Internet信息服务(IIS)管理器→右击本项目虚拟→属性,如下图

          (http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm01.JPG)

2、点击按钮“配置”,出现如下对话框:

(http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm02.JPG)

3、双击.aspx的应用程序扩展→查看对话框内容,如下图:

(http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm03.JPG)

4、复制“可执行文件”的全路径名称后→点击“取消”返回上一层对话框→点击按钮“添加”

5、粘贴刚才复制的内容(我的系统装在D盘,所以内容为D:"WINDOWS"Microsoft.NET"Framework"v1.1.4322"aspnet_isapi.dll)→填写后缀名为.htm→填写动作限制为“GET,HEAD,POST,DEBUG”(为方便省事你可选全部)

6、最后点击“确定”→往项目中添加HtmlPage1.htm→在IE浏览器的地址栏直接输入http://localhost/FormTest/HtmlPage1.htm→观看测试效果

最后送大家一段Web.config设置,发完睡觉,实在是困的不行了。

<location path="决战紫禁城">

<system.web>

<authorization>

<allow users="叶孤城"/>

<allow users="西门吹雪"/>

<deny users="*"/>

</authorization>

</system.web>

</location>

<location path="金銮殿屋脊">

<system.web>

<authorization>

<allow users="腰系缎带之人"/>

<deny users="*"/>

</authorization>

</system.web>

</location>

第三部分实现单点登录(SingleSignOn

“等了好久终于等到今天,写了好久终于就快完结,但是网友的反应却让我有一些的伤心。盼了好久终于盼到今天,忍了好久终于把此文撰写,那些受冷落的无奈早就无所谓,累也不说累”(歌词《今天》新演绎)。看着人家的Blog文章的评论是一条接一条,再瞧瞧自己:“无人问津呐,真…无…奈……唉,没人理我,还是回家吧。”“哎,还没开始写,怎么就走了?回去干什么呢?”回去写作业去啊,上回交待的课外作业你做了没?(注:http://blog.csdn.net/cityhunter172/archive/2005/11/13/528463.aspx在第二部分第六节布置的课外作业:此项目有两部门使用,其中每个部门分别都有些特定的页面仅供本部门用户浏览使用,请问该如何使用Web.config达到效果?)

不知有多少人做了作业,其实答案并不难。只需要在验证用户名与密码后,取得该用户的部门名称或部门代码,把它作为判断的依据就行了。最好不要用部门的数字ID,那样不利于以后的维护。

有一个秘密,一般人我不告诉他。Web.config中的<location>节点的path属性可以是一张具体页面的相对URL路径,如下:<location path="ManageSys/Auditing.aspx">

好了,接下来就要揭开“比根目录Web.config的作用范围还大的配置文件”之谜啦,它就是藏匿在Windows系统目录下,支配整个.NetFramework配置的传说中的Machine.config!!下面请大家以热烈的掌声,欢迎我们这位神秘侠客的闪亮登场……

九、Machine.config

Machine.config,性别不详,年龄未知,家庭出身:XML。深藏于“云深不知处”的操作系统目录下的某某地方(注:C:"WINDOWS【或WINNT】"Microsoft.NET"Framework"v1.1.4322【或v1.0.3705】"CONFIG),控制着“更上一层楼”的.NETFramework的本机配置。接下来简要的讲解一下它的内容,以及它与Web.config的关系。

经过“松下问童子”,我们好不容易找到这位隐者,打开一看,乖乖,足有3700多行!!“叫我怎么能不难过,偶只想看看是啥结构,可内容实在是太多太繁琐……”还记得偶经常对同事说的一句话么:“办法是人想出来的!”它不是有三千七百多行吗,那我们就不管三七能否得出二十一啦,把它拷出来先。它不是XML出身吗,那咱们就还其正身,重新命名为“machine.xml”。接着用IE浏览器将这位改头换面的隐者打开,把节点与注释一一合拢。这回你看到了吧,是不是很有成就感?你要是想谢谢我,就让我看到你在此文下面的评论吧。多多益善,呵呵。

Machine.config与Web.config是啥关系?四个字——父子关系。记得我在第二部分第五节讲解Web.config作用范围的时提到两点——继承与覆盖(详见http://blog.csdn.net/cityhunter172/archive/2005/11/13/528463.aspx),在此也同样适用。

1、Machine.config中的设置将作用于运行在本机的所有站点及其虚拟目录,遇到子目录将一直继承下去。

2、Web.config中的设置将覆盖由Machine.config中继承下来的对应的节点设置

说到这,再告诉大家一个秘密——“世上本无秘密,知道的人多了,便成了不是秘密的秘密!”

a、Machine.config中的<system.web>节点所有内容都能出现在项目根目录下的Web.config中,也就是说能在Web.config中的内容已经在Machine.config中一一列出;

b、其中<system.web>节点下的<pages>还能出现在页面上,如:HTML视图下,在WebForm1.aspx的第一行加上<pages>的节点内容validateRequest="false"(此句意思是不对WebForm1.aspx页面文本框输入的值,是否包含“<”“>”等等具有危险性的代码进行检查,下一节将具体运用到)

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="FromTest.WebForm1" validateRequest="false"%>

十、单点登录(SingleSignOn)的前提条件

之前说了这么多关于Machine.config的事,都是为了实现单点登录作铺垫,那何为单点登录(SingleSignOn)?从字面理解就是在一个地方登录,通常运用于ASP.NET分布式环境中(跨单个服务器上的多个应用程序或在网络场中)的Forms身份验证。打个比方,就好比现在Sohu(搜狐)与Chinren(中国校友录)的做法,我在Sohu登录以后就不需要在Chinaren登录了。台湾与香港又把SingleSignOn称之为“单一登入”。

要想实现此功能,首要条件是需要一组用于加密与验证加密的密钥。它们位于Machine.config中,修改<system.web>节点下的<machineKey>节点属性,如下:

<machineKey

firstKey="172"

copyrightKey="Cityhunter172"

validationKey="AD117F2F286CDCB15A9D1D4535E16DB0248026939**AUTHOR**CITYHUNTER172****WEBSITE**172*MEIBU*COM****MAILTO**CITYHUNTER172@126*COM*****F2F286CDCB15A9D1D4535E16DB0248026939"

secondKey="meibu"

decryptionKey="3C89AE62AD117F2F286CDCB15A9D1D4535E16DB0248026939" validation="SHA1"

thirdKey="com"

/>

1、validationKey为用于验证加密数据的密钥。最小长度为40个字符(20字节),最大长度为128个字符(64字节)。

2、decryptionKey为用于加密数据的密钥。长度只有16个字符(8字节)与48个字符(24字节)两种。

3、validation为用数据验证使用的加密类型。拥有“SHA1”“MD5”“3DES”三种方法

4、大伙参照上述<machineKey>试着在WebForm1.aspx运行下列语句:

this.TextBox2.Text="ht"+"tp"+"://"+firstKey+"."+secondKey+"."+thirdKey

大家在修改之前请先备份一下Machine.config,到时要是出错可别怪我没提醒你。以上密钥并不是胡乱得来的,接下来向大家介绍生成密钥的方法。

我们把上一节中提到的WebForm1.aspx拖入本项目的Public目录下,再往页面上拖入一个TextMode=MultiLine的TextBox3与一个Button编写按钮事件与函数:

privatevoidButton1_Click(objectsender,System.EventArgse)

{

stringdecStr=this.CreateKeyString(int.Parse(this.TextBox1.Text));

stringvalStr=this.CreateKeyString(int.Parse(this.TextBox2.Text));

this.TextBox3.Text=string.Format("<machineKeyvalidationKey=""{0}""decryptionKey=""{1}""validation=""SHA1""/>",valStr,decStr);

}

///<summary>

///生成加密型强随机Key值

///</summary>

///<paramname="i">Key的有效长度:

///decryptionKey的有效值为8或24;

///validationKay的有效值为20至64

///</param>

privatestringCreateKeyString(inti)

{

System.Security.Cryptography.RNGCryptoServiceProvider rng=newSystem.Security.Cryptography.RNGCryptoServiceProvider();//加密随机数生成器

byte[]bt=new byte[i];

rng.GetBytes(bt);//用加密型强随机值序列填充字节数组

System.Text.StringBuilder str=newSystem.Text.StringBuilder();

for(intj=0;j<i;j++)

{

str.Append(string.Format("{0:X2}",bt[j]));//转换成大写的十六进制文本

}

returnstr.ToString();

}

每次点击按钮生成密钥都不同,大家不妨多点几次。切换至HTML视图,到WebForm1.aspx第一行把validateRequest="false"去掉,然后再多点几次Button1试试,看看会有什么效果,嘿嘿………

十一、单点登录(SingleSignOn)的站点示例

将上述TextBox3产生的文本,覆盖Machine.config中的,现在你的机器已经具备了单点登录的条件。大伙可以再新建一个项目FormTest2,从FormTest2登录后直接输入FormTest中的Default.aspx的网址(http://localhost/FormTest/Default.aspx),反之亦可。

下面结合实例讲解:偶在山东每步科技网站申请了一个免费二级域名172.meibu.com,并下载了每步的4.0版的动态域名解析客户端。现在使用ADSL拔号上网,也就是说我的电脑已经成了Web服务器,同时支持SQLServer、Oracle空间高达200G想怎么弄就怎么弄,够牛吧,嘿嘿。布署上来的项目有环胜数码网站、权限管理系统、IT内部管理网,以上三个项目是偶一人全权开发的。所谓全权就是从数据库存储过程写到.cs代码再到javascript,最后到美工都是偶一手搞定的。^_^我把这三个不相干的项目做成了单点登录的模式,加上整合站点的主页面,共有四个地方可以进行登录。因为用户Table的结构不同,因此只有一个入口能在进入后,在跳转站点时不会出错,那就是在整合页面登录。

现在我想把环胜数码这个站点单独脱离出来,而剩下的两个站点继续实现单点登录,该怎么做呢?或者是我的ASP.NET的空间是租的,服务商肯定不可能让我修改Machine.config,我又咋办哩?“办法是人想出来滴!!”,根据上述Machine.config与Web.config的关系,我们可以把<machineKey>节点放入项目根目录下Web.config的<system.web>节点。如下:

1、权限管理系统项目的Web.config用于Form认证的设置

<machineKeyvalidationKey="AD117F2F286CDCB15A9D1D4535E16DB0248026939**AUTHOR**CITYHUNTER172****WEBSITE**172*MEIBU*COM****MAILTO**CITYHUNTER172@126*COM*****F2F286CDCB15A9D1D4535E16DB0248026939"decryptionKey="3C89AE62AD117F2F286CDCB15A9D1D4535E16DB0248026939"validation="SHA1"/>

<authenticationmode="Forms">

<formsloginUrl="Login.aspx"name="172.MEIBU.COM_WARRANT"></forms>

</authentication>

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

2、IT内部管理网项目的Web.config用于Form认证的设置

<machineKeyvalidationKey="AD117F2F286CDCB15A9D1D4535E16DB0248026939**AUTHOR**CITYHUNTER172****WEBSITE**172*MEIBU*COM****MAILTO**CITYHUNTER172@126*COM*****F2F286CDCB15A9D1D4535E16DB0248026939"decryptionKey="3C89AE62AD117F2F286CDCB15A9D1D4535E16DB0248026939"validation="SHA1"/>

<authenticationmode="Forms">

<formsloginUrl="Login.aspx"name="172.MEIBU.COM_IT"></forms>

</authentication>

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

大家可能会迫不急待的去试一把,偶赞成这样的做法,因为事实是检验真理的唯一办法。你不去试着自己动手,光看我在这说是很难提高的。先别急,我已经知道你想说什么,听听我慢慢向你解释:

a)两个项目Web.cinfig的<machineKey>节点确保以下几个字段完全一样:validationKey、decryptionKey、validation

b)两个项目的Cookie名称必须相同,也就是<forms>中的name属性,这里我们把它统一为name="172.MEIBU.COM_PROJECT"

c)注意区分大小写

在整合的过程中,我把遇到的问题向大伙说一下,以免你们走同样的路。

1)首先应该是用户管理的问题,把两个项目的用户整合在一起,可不是一件容易的事,原则是新建一个新的Table只存放帐号与密码,用账号做关联,编写触发器,做到Table之间的同步;

2)不要指望两个项目间用Session进行传值,两个应用程序的Session是无法共享的。网上有人曾把类库(编译后的.dll文档)放入同一个bin文件夹实现过Session共享,这样的做法实际上是把两个项目变相合并成一个应用程序,不是我们所想要的,理由很简单:Sohu与Chinaren的服务器分处两地该怎么办?

3)项目间的传值,可用Cookie实现。在第一部分的第三节(http://blog.csdn.net/cityhunter172/archive/2005/11/06/524043.aspx)我们介绍了只要运行System.Web.Security.FormsAuthentication.SetAuthCookie方法即可实现登录,单点登录的实质就是含有身份验证票的Cookie能在项目间共用。

接下来,有必要向大家介绍一下Cookie在.Net中的用法。

十二、CookieASP.NET中的用法

大家也许和我一样,很少在ASP.NET中使用Cookie,传参数呀,存变量呀,用的比较多的是Session或ViewState以及隐藏控件,有的干脆用“?”的请求方式。

1、Cookie存放的目录

Cookie是存放在客户端的东东,放在“TemporaryInternetFiles”目录,所以说存在安全性的问题。大伙可通过以下方式找到具体位置:打开控制面板→Internet选项→常规→Internet临时文件→设置→即可看到“当前位置”,→点击“查看文件”将直接打开该文件夹,你也可以点击“移动文件夹”变更它所在的位置。参照下图(http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm04.jpg与http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm05.jpg)

2、Cookie的有效期

从上图我们可以清楚的看到每个Cookie文档的“截止期”(即为有效期)。在有效期内,当登录计算机的用户Administrator再次访问172.meibu.com时,那么IE就会在请求页面的同时,连同上述的名称为“Cookie:administrator@172.meibu.com”的Cookie文档内容一起发送给服务器。

若该文档包含多个Cookie的值时,截止期则以最后的失效期为准。

3、Cookie的类型

这里我们按有效期来分,分为两种:

a)即时型

指的是关闭浏览器(所有浏览172.meibu.com的IE)后,Cookie便失效,此类Cookie不会在“TemporaryInternetFiles”目录出现。其实它也有截止期的,为“0001-01-01”

b)持久型

就是已指定具体“截止期”的,能够在“TemporaryInternetFiles”目录里面找到的Cookie

4、Cookie的内容

双击打开“Cookie:administrator@172.meibu.com”,我们看到以下内容,如下图(http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm06.jpg):

上图中,“■”是换行符,你若是要打破什么锅来问我到底是怎么知道的话。我倒是会很乐意的告诉你:这就是经验!偶从学习C#那刻起,就拿第一个Windows程序——记事本来开刀,保存文档时得来的经验。

所以服务器读出来的格式如下图(http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm07.jpg):

5、在ASP.NET页面发放Cookie

发送上述Cookie的.cs代码为:

System.Web.HttpCookie ck=new HttpCookie("ckValue0");

ck["Author"]="CityHunter";

ck.Expires=System.DateTime.Now.AddMinutes(10);//若不指定,则为即时型Cookie

//ck.Path="/FormTest/ManageSys";//设置Cookie的虚拟路径,注意一定要以“/”开头,否则为无效Cookie;请大家自行看一下它与在客房端的Cookie文档“名称”与“Internet地址”的关系

Response.Cookies.Add(ck);

ck=newHttpCookie("ckValue1");//重新新建一个名为ckValue1的Cookie

ck.Expires=System.DateTime.Now.AddMinutes(20);//即刻起20分钟后失效

ck["E_Mail"]="cityhunter172@126.com";//设置ckValue1中的E_Mail值

ck["PersonalWeb"]="172.meibu.com";

Response.Cookies.Add(ck);//添加此Cookie

6、取回已发放Cookie的值

Response.Write(Request.Cookies["ckValue0"]["Author"]+"<br>");//用不着说明了吧

Response.Write(Request.Cookies["ckValue1"]["E_Mail"]+"<br>");

Response.Write(Request.Cookies["ckValue1"]["PersonalWeb"]);

好久没有出作业啦(何出此言?),这第三篇呀,可是花了偶两个星期的业余时间调试、总结、撰写哪,都说时光贵如金,不知我花的这些时间能换来多少银子?换银子,我看是没指望啦,能得到阁下的一句评论,偶也满足了。记住,你的评论就是偶继续写下去的动力。

作业:给Cookie赋于以下值,怎样得到它的正确值

ck["str1"]="2222";

ck["str"]="str0=11111&str1=223";

可以肯定的是Request.Cookies["ckValue1"]["str"]得不到“str0=11111&str1=223”这个字串,大家不妨试一下Request.Cookies["ckValue1"]["str1"]会得到意想不到的字串哟。

提示:使用Server.UrlEncode()与Server.UrlDecode()

十三、发放永久性的验证Cookie

终于……终于……最后一个章节,蓦然回首,洋洋洒洒十二章。没想到年少时写不完作文的偶,居然也能编出几千余字的文章来呀,不得不佩服偶自己呀!再回首,一大片晕倒的人……。永远到底有多远?永久究竟是多久?只有天知道。

大家登录CSDN的时候是否留意到一个“2周内不用再登录”的复选框,它又是怎么做到的呢?大家是否曾遇到过这样的困惑:在执行System.Web.Security.FormsAuthentication.SetAuthCookie时明明已指定createPersistentCookie为true为何关闭浏览器仍不能直接访问网站?下面我们就这个问题给大家解释一下,且介绍如何手工创建身份验证票并加入Cookie中。

System.Web.Security.FormsAuthenticationTicket tk=newSystem.Web.Security.FormsAuthenticationTicket(

1,//指定版本号:可随意指定

"Admin",//登录用户名:对应Web.config中<allowusers="Admin"…/>的users属性

System.DateTime.Now,//发布时间

System.DateTime.Now.AddYears(100),//失效时间:100年以后,够永够久了吧

false,//是否为持久Cookie:尚未发现有何用,至少目前偶还不知,下面会有说明

"测试用户数据"//用户数据:可用((System.Web.Security.FormsIdentity)User.Identity).Ticket.UserData获取

);

stringstr=System.Web.Security.FormsAuthentication.Encrypt(tk);//加密身份验票

//声明一个Cookie,名称为Web.config中<formsname=".APSX"…/>的name属性,对应的值为身份验票加密后的字串

System.Web.HttpCookieck=newHttpCookie(System.Web.Security.FormsAuthentication.FormsCookieName,str);

//指定Cookie为Web.config中<formspath="/"…/>path属性,不指定则默认为“/”

ck.Path=System.Web.Security.FormsAuthentication.FormsCookiePath;

//此句非常重要,少了的话,就算此Cookie在身份验票中指定为持久性Cookie,也只是即时型的Cookie关闭浏览器后就失效;因此上面我说:我是真的还不知在身份验票中指定为持久性Cookie有何用。

ck.Expires=System.DateTime.Now.AddYears(100);

Response.Cookies.Add(ck);//添加至客房端

后记

此系列文章共三部分,历时一个月完成(2005-11-05~2005-12-06)。以上是我学习并用于实践的一些经验,在此拿出来与大家一起分享。代码都是经过调试的,如有任何疑问,可在CSDN论坛(http://community.csdn.net/)找到我,我的ID是cityhunter172(可用此ID发短消息给我),昵称为寒羽枫,欢迎大家批评指正。

第四部分Form认证的补充

前三篇在CSDN论坛公布后,效果如同“神仙放屁——果然不同凡(反)响”。为感谢广大网友的热情与支持,这不,经过这一阵子的酝酿、修炼,特意准备了这第四响。

之前我们讲述的使用Form认证实现单点登录,正如网友所说的那样,只能在同一域名下使用。对于跨域名的单点登录,除了使用Passport认证外,我们还是可以用Form认证的,只是要讲究方法而已啦。正所谓“山不转水转,人不转心转”。

一、跨域名的解决思路

在MSDN2003上搜索关键字“Passport”,偶找到一篇“Passport身份验证提供程序”。文章讲述了Passport的认证原理,共8条,我就不多说了,大伙自个看吧。其中有一句话,引起偶的注意:“……响应在查询字符串中包含一个加密的Passport Cookie……”。也正是此句才有了下面的思路。

所谓认证的通过与否,其实质就是检测有无发放有效的Cookie,使用Form也好,运用Passport也罢,都是Cookie在起作用。也就是说,我们只要把有效的Cookie在登录后一次性发放给客户端就得了。

二、跨域名、跨服务器的单点登录方法

1、如何在本机模拟跨域名、跨服务器的SingleSignOn

只要浏览网址不同就相当于不同域名,在本机至少有以下三种。它们虽然是同一项目,彼此却不能共用Session与Cookie,也就无法共享身份验证票:

a).http://localhost/FormTest/Login.aspx

b).http://127.0.0.1/FormTest/Login.aspx

c).http://My_Computer_Name/FormTest/Login.aspx//以电脑名称浏览站点

d).http://192.168.0.8/FormTest/Login.aspx//以网卡地址浏览站点

e).http://172.meibu.com/FormTest/Login.aspx//拥有国际域名

2、在ASP.NET中如何提交给其它页面

用过ViewState的大概都知道,ViewState是保存在客户端的。不知大伙注意没有,ASP.NET为每张.aspx页面都配备了独自的ViewState,且被解析后都是以一个name="__VIEWSTATE"的隐藏控件值来保存ViewState。每次页面提交,服务器都会检查该控件的值有无被篡改,如此一来就注定.aspx只能提交给本页。服务器是死的,人是活的,我们不能被这些条条框框限定死了,我们要把程序写成活的。

下面咱们从http://localhost/FormTest/Login.aspx输入用户名与密码,然后提交给http://127.0.0.1/FormTest/Public/LoginTransfer.aspx。Login.aspx与LoginTransfer.aspx都包含用户名输入框一个、密码输入框一个、登录按钮一个。在Login.aspx页面加入以下代码:

this.Btn_Login.Attributes["onclick"]="SingleSignOn()";//指定执行脚本事件

在Login.aspx页面上插入以下脚本:

<script language="javascript">

Function SingleSignOn()

{

//只能用脚本改变指定Form提交的对象

document.getElementById("Form1").action="http://127.0.0.1/FormTest/Public/LoginTransfer.aspx?FromUrl="+window.location.href;

//把隐藏控件__VIEWSTATE中的值变更为LoginTransfer.aspx解析后出现的值,以实际看到的值为准

document.all.__VIEWSTATE.value="dDwtMTkyODUzMTMyNzs7Pv1cp2RaxUcr5hGYf8ILX9/EMKy8";

}

</script>

注意事项

a).LoginTransfer.aspx出现的控件及其ID,必须能够在Login.aspx找到

b).控件的ID必须一致,且能一一对应

c).关于__VIEWSTATE中的值,它与页面控件ID无关,与浏览该页面的网址无关,目前我只知道和控件的数量、类型、名字空间(namespaceFormTest.Public)以及存在的ViewState有关系。大家在测试时,以直接浏览http://127.0.0.1/FormTest/Public/LoginTransfer.aspx后,查看页面源文件所看到的值为准。

d).提交后,将触发并执行LoginTransfer.aspx中的Btn_Login_Click事件

3、基本思路

各个站点的登录页面统一将用户名与密码提交给LoginTransfer.aspx,同时各个站点需要一个增加Cookie的页面,用于将加密后的身份验证Cookie添加至客户端。此乃经过一番考量后,最终确定的可行性方案。

4、第一种思路——天女散花

何谓天女散花,就是把Cookie在登录后一次性全发放出去,就如同天仙在空中散花一样,场面是何等的壮观。下面开始写代码:

为更好的区分,我们将负责添加Cookie的页面分开命名:

a).http://localhost/FormTest/Public/AddCookie_A.aspx

b).http://127.0.0.1/FormTest/Public/AddCookie_B.aspx

c).http://My_Computer_Name/FormTest/Public/AddCookie_C.aspx

这三张页面的功能一样,所以代码也就相同啰

privatevoidPage_Load(objectsender,System.EventArgse)

{

stringfrom=Request["FromUrl"];//起始URL路径

stringnext=Request["NextUrl"];//还需要跳转的URL

stringkey=Request["CookieTicket"];//已加密的Cookie文本

if(key!=null&&key!="")

{

System.Web.HttpCookieck=newHttpCookie(System.Web.Security.FormsAuthentication.FormsCookieName,key);

ck.Path=System.Web.Security.FormsAuthentication.FormsCookiePath;

ck.Expires=System.DateTime.Now.AddYears(100);

Response.Cookies.Add(ck);//将传过来的已加密的身份验证票添加至客房端

stringurl=next.Split(';')[0];//从URL中拆分出将要跳转的下一张页面

next=next.Replace(url+";","");//带入下一轮跳转的字串

if(url!="")

{

//跳至下一页面Response.Redirect(url+"?CookieTicket="+key+"&FromUrl="+from+"&NextUrl="+next);

}

else//已没有下一页面可供跳转

{

Response.Redirect(from);//回到起始页面

}

}

}

接下来编写LoginTransfer.aspx的代码:

//页面常量allLoginUrl存放所有站点的AddCookie.aspx的URL,注意以;分隔

publicconststringallLoginUrl=

"http://localhost/FormTest/Public/AddCookie_A.aspx;"

+"http://127.0.0.1/FormTest/Public/AddCookie_B.aspx;"

+"http://My_Computer_Name/FormTest/Public/AddCookie_C.aspx;";

偶已在上面讲述了,如何点击Login.aspx中的登录按钮Btn_Login将用户名与密码提交给LoginTransfer.aspx,并执行LoginTransfer.aspx中的Btn_Login_Click事件。

privatevoidBtn_Login_Click(objectsender,System.EventArgse)

{

stringfrom=Request["FromUrl"];//起始URL路径

stringnext=this.allLoginUrl;

//由于控件ID相同,所以此处得到的是由Login.aspx提交过来的用户名与密码

if(this.Txt_LoginName.Text=="Admin"&&this.Txt_Password.Text=="123456")

{

System.Web.Security.FormsAuthenticationTickettk=newSystem.Web.Security.FormsAuthenticationTicket(1,"Admin",System.DateTime.Now,System.DateTime.Now.AddYears(100),false,"测试用户数据");

stringkey=System.Web.Security.FormsAuthentication.Encrypt(tk);//得到加密后的身份验证票字串

stringurl=next.Split(';')[0];//从URL中拆分出将要跳转的下一张页面

next=next.Replace(url+";","");//带入下一轮跳转的字串

Response.Redirect(url+"?CookieTicket="+key+"&FromUrl="+from+"&NextUrl="+next);//跳至下一页面

}

}

5、第二种思路——后羿射日

后羿射日,意思指的是用户点哪就跳哪。他若是点“火坑”,你也得往里跳,因为用户是上帝嘛。我们增加一个通行证页面MyPassport.aspx,由http://127.0.0.1/FormTest/Public/LoginTransfer.aspx发放验证Cookie后直接跳转至http://127.0.0.1/FormTest/MyPassport.aspx。不要告诉我你不会,你要是真不会,那偶也没法子啦,还得请你回头看看,偶在第三篇是如何讲述发放永久性验证Cookie吧(http://blog.csdn.net/cityhunter172/archive/2005/12/06/545301.aspx)。还需要一张用作跳板的跳转页面MyTransfer.aspx。

MyPassport.aspx的代码:

<atarget="_blank"

href="MyTransfer.aspx?goto=http://localhost/FormTest/Public/AddCookie_D.aspx">

美丽的天使</a>

<atarget="_blank"

href="MyTransfer.aspx?goto=http://127.0.0.1/FormTest/Public/AddCookie_E.aspx">

快乐的天堂</a>

<atarget="_blank"

href="MyTransfer.aspx?goto=http://My_Computer_Name/FormTest/Public/AddCookie_F.aspx">

大大的火坑</a>

MyTransfer.aspx的代码:

privatevoidPage_Load(objectsender,System.EventArgse)

{

//获取身份验证票

System.Web.Security.FormsAuthenticationTickettk=((System.Web.Security.FormsIdentity)User.Identity).Ticket;

stringkey=System.Web.Security.FormsAuthentication.Encrypt(tk);//每次加密后的字串都是不同的

stringnext=Request["goto"];//将要跳转的URL

Response.Redirect(url+"?CookieTicket="+key);//跳转至下一页面

}

AddCookie_D.aspx、AddCookie_E.aspx、AddCookie_F.aspx这三张页面的代码:

stringkey=Request["CookieTicket"];//已加密的Cookie文本

if(key!=null&&key!="")

{

System.Web.HttpCookieck=newHttpCookie(System.Web.Security.FormsAuthentication.FormsCookieName,key);

ck.Path=System.Web.Security.FormsAuthentication.FormsCookiePath;

ck.Expires=System.DateTime.Now.AddYears(100);

Response.Cookies.Add(ck);//将传过来的已加密的身份验证票添加至客房端

Response.Redirect("../Index.aspx");//跳转至你真正想带客户去的地方

}

6、点评

两者共同点:

a).每个站点都需要一个登录的提交点、一张添加Cookie的页面。

b).因为只能靠发放验证Cookie来识别身份,所以一台电脑不能同时登录两个帐号。

c).都存在不同程度的安全隐患。

两者不同点:(天女散花以下简称“开女”,后羿射日就简称“后羿”)

a).天女一次性发放Cookie,如果站点较多,处理起来还是需要一些时间的。而后羿则相反,站点再多也不怕。

b).天女在散花的过程中,如果中途被卡住,则需要一个错误处理机制做回退处理。后羿则不需要。

c).天女在登录后可以直接在IE地址浏览其想看的站点;而后羿则必须从通行证的跳板页面进入才行。

根据上述问题,给几点建议:

a).不要使用永久性Cookie,应指明身份验证票的过期时间,注意不是Cookie的有效期。

b).在身份验证票的UserData中加入其它的验证信息或存放用户ID

c).在网络通畅的情况下,比如局域网,站点又相对较少,建议选用天女。50个站点之间做跳转应该不会超过10秒(前提是已编译好了,且不是初次访问)。

三、跨域名、跨服务器的退出方法

只要理解了“天女散花”,退出就比较容易啦。为每个站点准备一个用于退出的页面,如下:

a).http://localhost/FormTest/Public/Logout.aspx

b).http://127.0.0.1/FormTest/Public/Logout.aspx

c).http://My_Computer_Name/Public/FormTest/Logout.aspx

privatevoidPage_Load(objectsender,System.EventArgse)

{

System.Web.Security.FormsAuthentication.SignOut();//删除Cookie中的身份验证票

stringfrom=Request["FromUrl"];

stringnext=Request["NextUrl"];

stringurl=next.Split(';')[0];

next=next.Replace(url+";","");

if(url!="")

{

Response.Redirect(url+"?FromUrl="+from+"&NextUrl="+next);

}

else

{

Response.Redirect(from);

}

}

转载于:https://www.cnblogs.com/yexinw/archive/2011/09/15/2178134.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380231.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

添加LinkServer的两句代码

sp_addlinkedserver linkserver,,SQLOLEDB,linkserver.comsp_addlinkedsrvlogin linkserver,false,null,sa,asdf第一句是添加一个名字为linkserver的链接服务器 地址是linkserver.com第二句是针对第一句添加的Linkserver添加一个访问帐号两句不能同时执行 要第一句执行成功后执…

数组的基本查找

package asdasqq; import java.util.*; public class jibenchazhao { public static void main(String[] args) { int [] arr{11,22,33,44,55,66,77}; Scanner wsqnew Scanner(System.in); int qwsq.nextInt();//输入q&#xff0c;即为查找的数&#xff1b; int index g…

Cobaltstrike4.0系列教程(一)----简介与安装

0x01-Cobaltstrike简介 Cobalt Strike是一款美国Red Team开发的渗透测试神器&#xff0c;常被业界人称为CS。这款神器许多大佬们都已经玩的很6&#xff0c;我一个菜鸡玩的略有心得&#xff0c;因此写一下自己的Cobaltstrike系列文章&#xff0c;希望给各位一点帮助。 最近这个…

c ++类成员函数_仅使用C ++创建具有公共数据成员的类

c 类成员函数Let’s understand 让我们来了解 What is data member? 什么是数据成员&#xff1f; Any variable declared inside the class in known as data member of the class. 在类内部声明的任何变量&#xff0c;称为类的“数据成员”。 What is public data member…

转:php.ini中文版

[PHP] ; PHP还是一个不断发展的工具&#xff0c;其功能还在不断地删减 ; 而php.ini的设置更改可以反映出相当的变化&#xff0c; ; 在使用新的PHP版本前&#xff0c;研究一下php.ini会有好处的 ;;;;;;;;;;;;;;;;;;; ; 关于这个文件 ; ;;;;;;;;;;;;;;;;;;; ; 这个文件控制了PHP许…

qt 试用 (3)配置编译源代码及调试

qt 试用 &#xff08;3&#xff09;配置编译源代码及调试qt creater是一个集成ide&#xff0c;像vc一样容易使用&#xff0c;所以首先下载带qt creater的qt sdk Offline installer - 1.4 GB http://qt.nokia.com/downloads/sdk-windows-cpp-offline这里的lib没有pdb和源代码…

两数的最大公约数算法基础及优化

最大公约数算法师从辗转相除法&#xff08;欧几里得算法&#xff09;时间复杂度更相减损术&#xff08;《九章算术》&#xff09;时间复杂度二分化更相减损术思路优化时间复杂度师从 本篇是观Vita君算法视频后总结&#xff0c;他是bilibili一位小up主&#xff1a;小学生Vita君…

cobaltstrick4.0系列教程(2)---用户接口

0x01 概述 Cobalt Strike 用户接口分为两部分。接口的顶部是会话或目标的视觉化展示。接口的底部展示了每个你与之交互的 Cobalt Strike 功能或会话的标签页。你可以点击这两部分之间的区域、按你的喜好重新调整这两个区域的大小。 0x02 工具条 Cobalt Strike 顶部的工具条…

java类名与文件名_为什么Java文件名必须与公共类名相同?

java类名与文件名The question is that "Can we keep different names for java class name and java file name?" 问题是“我们可以为Java类名和Java文件名保留不同的名称吗&#xff1f;” Yes, we can keep the different name for the java filename and java c…

玩什么都别玩暧昧

暧昧 这个介于朋友与情人间的关系 能给予寂寞的人些须安慰与短暂的幸福感 暧昧 没有任何承诺 彼此都不向对方许下诺言 没有甜言蜜语 没有海誓山盟 却在彼此悲伤难过的时候 给予彼此依靠 也许 这种关系是最好的 因为它不虚假 它没有骗人的谎言 因为彼此没有承诺 两个人 可以一起…

快速幂模

快速幂模简述师从普通思路缺陷一&#xff1a;溢出缺陷二&#xff1a;运算次数多二分化快速幂模简述 计算 ana^nanmod p 师从 本篇是观Vita君算法视频后总结&#xff0c;他是bilibili一位小up主&#xff1a;小学生Vita君 正所谓“生乎吾后&#xff0c;其闻道也亦先乎吾&#…

《那些年啊,那些事——一个程序员的奋斗史》——31

“我们再重新找房吧&#xff1f;”伍定轩对段伏枥说道。“为什么&#xff1f;”段伏枥突然觉得奇怪&#xff0c;为何伍定轩会突然提出这个问题。“你看我的仙人掌。”伍定轩指了指摆在电脑旁边的一盆仙人掌。当初伍定轩决定买这小盆仙人掌的时候&#xff0c;也是从网上听人说&a…

数煤球

煤球数目 有一堆煤球&#xff0c;堆成三角棱锥形。具体&#xff1a; 第一层放1个&#xff0c; 第二层3个&#xff08;排列成三角形&#xff09;&#xff0c; 第三层6个&#xff08;排列成三角形&#xff09;&#xff0c; 第四层10个&#xff08;排列成三角形&#xff09;&…

cobalt strick 4.0系列教程(3)---数据管理

0x01 概述 Cobalt Strike 的团队服务器是行动期间 Cobalt Strike 收集的所有信息的中间商。Cobalt Strike 解析来自它的 Beacon payload 的输出&#xff0c;提取出目标、服务和凭据。 如果你想导出 Cobalt Strike 的数据&#xff0c;通过 Reporting → Export Data 。Cobalt S…

JavaScript中的交互式网页/事件处理

Programming languages like C, C etc are all based on synchronous coding approach i.e. the execution takes place from top to bottom in a linear manner. 诸如C&#xff0c;C 等编程语言均基于同步编码方法&#xff0c;即执行以线性方式从上到下进行。 But JavaScript…

2008来了,搬个凳子先

此帖为证. 转载于:https://www.cnblogs.com/margiex/archive/2008/01/01/1022098.html

题目收藏夹(自用)

题目收藏夹&#xff08;自用&#xff09; 计数质数 【埃氏筛】【线性筛】

calayer 与uiview

研究Core Animation已经有段时间了&#xff0c;关于Core Animation&#xff0c;网上没什么好的介绍。苹果网站上有篇专门的总结性介绍&#xff0c;但是似乎原理性的东西不多&#xff0c;看得人云山雾罩&#xff0c;感觉&#xff0c;写那篇东西的人&#xff0c;其实是假 设读的人…

代换-置换网络(SP网络)

0x01 概述 代换-置换网络是一系列被应用于分组密码中相关的数学运算&#xff0c;高级加密标准&#xff08;英语&#xff1a;AES&#xff09;、3-Way、Kuznyechik、PRESENT、SAFER、SHARK、Square都有涉用。这种加密网络使用明文块和密钥块作为输入&#xff0c;并通过交错的若干…

Java SecurityManager getSecurityContext()方法与示例

SecurityManager类的getSecurityContext()方法 (SecurityManager Class getSecurityContext() method) getSecurityContext() method is available in java.lang package. getSecurityContext()方法在java.lang包中可用。 getSecurityContext() method is used to return an ob…