|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
关于第二点:俺问问你,如果是企业级项目的话,诸如RMI,EJB,等一些关键技术,这些难道都不需要学么?如果光是使用jsp,servlet,javabean的话。会见|把持
jungleford如是说平安性是Java宣传得最多的特征之一,切实其实,Java的平安特征涵盖了从使用级别到言语级别以致JVM自己。之前人人都晓得有个Sandbox,但唯一Sandbox尚不克不及满意,大概说不克不及很便利地做到我们所必要的全体平安需求,比如如今一个体系起首最少必要一个登录功效,更进一步的话,还必要对用户会见资本的举动举行束缚,上面我想大抵讲一下Java是如何做这些事变的,基础上是一个总结大概说是“读后感”的性子,同时给出一个复杂的完成例子,这个例子实在仍是仿照人家的,呵呵……
1.Java的会见把持机制
谈到会见把持,大概说“受权”,这里有两层寄义,一是从资本的角度,这个socket端口是不是被同意操纵?这个文件是可读的?可写的?仍是可实行的?仍是以上都行?这就是我们在UNIX下用“ls-l”命令列出以后目次下文件时,那些“-rwx-”之类的寄义;二是从会见者的角度,我想经由过程80端口看Web上新浪欧洲杯的旧事,在这个体系中有无这个资历?我想播放D盘上一个名为“friends.rm”的视频文件,我失掉了会见这个文件的权限了吗?我有运转播放器的权限吗?Java在会见把持战略上同时思索了这两方面内容,你说“不合错误呀,我用FileOutputStream写文件,用Socket类毗连远程主机都用得好好的,没甚么限定呀”,这我们得先谈谈甚么叫做“平安办理器”(SecurityManger)。平安办理器从JDK1.0就入手下手有了,多陈旧啊!Java从计划的那一天入手下手就思索了平安要素,平安办理器是Sandbox的最主要的一个部分,也是会见把持的总和谐者,我们可以在一般情形下一般利用收集和文件,那是由于当启动application的时分(注重是application,不是applet!),假如你不加“-Djava.security.manager”选项,JVM是不会启动Sandbox的,这时候你能够“随心所欲”,而不会碰着SecurityException之类的非常;一旦到场了“-Djava.security.manager”选项,你就会发明有连续串的非常呈现喽!Exceptioninthread"main"java.security.AccessControlException:accessdenied(……)……Java内置了一个默许的平安战略,这类情形下平安办理器起首装载的是这个默许的战略,不信啊,不信你反省一下你的“%JAVA_HOME%jrelibecurity”目次,是否是有个叫“java.policy”的文件?用notepad翻开看看:
//StandardextensionsgetallpermissionsbydefaultgrantcodeBase"file:${java.home}/lib/ext/*"{permissionjava.security.AllPermission;};//defaultpermissionsgrantedtoalldomainsgrant{//Allowsanythreadtostopitselfusingthejava.lang.Thread.stop()//methodthattakesnoargument.//Notethatthispermissionisgrantedbydefaultonlytoremain//backwardscompatible.//Itisstronglyrecommendedthatyoueitherremovethispermission//fromthispolicyfileorfurtherrestrictittocodesources//thatyouspecify,becauseThread.stop()ispotentiallyunsafe.//See"http://java.sun.com/notes"formoreinformation.permissionjava.lang.RuntimePermission"stopThread";//allowsanyonetolistenonun-privilegedportspermissionjava.net.SocketPermission"localhost:1024-","listen";//"standard"properiesthatcanbereadbyanyonepermissionjava.util.PropertyPermission"java.version","read";permissionjava.util.PropertyPermission"java.vendor","read";permissionjava.util.PropertyPermission"java.vendor.url","read";permissionjava.util.PropertyPermission"java.class.version","read";permissionjava.util.PropertyPermission"os.name","read";permissionjava.util.PropertyPermission"os.version","read";permissionjava.util.PropertyPermission"os.arch","read";permissionjava.util.PropertyPermission"file.separator","read";permissionjava.util.PropertyPermission"path.separator","read";permissionjava.util.PropertyPermission"line.separator","read";permissionjava.util.PropertyPermission"java.specification.version","read";permissionjava.util.PropertyPermission"java.specification.vendor","read";permissionjava.util.PropertyPermission"java.specification.name","read";permissionjava.util.PropertyPermission"java.vm.specification.version","read";permissionjava.util.PropertyPermission"java.vm.specification.vendor","read";permissionjava.util.PropertyPermission"java.vm.specification.name","read";permissionjava.util.PropertyPermission"java.vm.version","read";permissionjava.util.PropertyPermission"java.vm.vendor","read";permissionjava.util.PropertyPermission"java.vm.name","read";};能够看到,JVM给沙箱内的application分派的权限仅限于中断线程,监听1024以上的TCP端口,和对一些体系属性的读取权限,像一样平常的socket操纵和文件操纵的权限都没有。懂得了平安办理器的观点今后我们回到受权成绩下去。对用户来讲,最忧虑的莫过于呆板中病毒,病毒实质上是一种歹意的程序,以是会见把持起首是要对代码的权限举行把持,下面我一向都在谈Sandbox,也就是所谓的“沙箱”,熟习Java平安性开展汗青的伴侣也许对它不会生疏,早期的Java是接纳如许一种平安战略,即:当地代码是可托的,而远程代码是不成信的,比如applet是一种从收集高低载到当地并在扫瞄器上运转的一段远程代码,因此是不成信的,以是初期的applet被完整置于Sandbox傍边,失掉的权限长短常无限的;在1.0今后,直至Java2呈现之前,平安战略作了一些天真的改动,applet不再是完整被卑视的“二等国民”了,由于有了署名applet,用户能够选择信托这类经由署名的applet,从而applet也能够做一些之前被以为是“特别”的事变;到了Java2,情形又变了,之前一直被信托的当地代码仿佛也变得不是那末牢靠了,这还真说禁绝,难保谁不会在你进来跟女伴侣逛街的时分,偷偷溜出去在你呆板上拷个病毒甚么的^_^,如许当地代码就落到了和远程代码相称同的位置了,这是对照切合实际天下场景的,在Java2中的平安战略被称之为“可设置的平安战略”,任何代码,只需是经由过程平安办理器会见,就必需为它事后设定好会见权限,在这个以外的资本仍是其余甚么东东,对不起,java.security.AccessControlException:accessdenied……此路欠亨!
复杂总结一下Java平安模子的开展史,也许就是上面的几幅图了:因为如今广泛是多用户的体系,以是在完成代码级会见把持以外,我们还但愿可以对用户的举动举行束缚,由于对体系形成损坏的要素不单单是歹意代码,人本身的成心或偶然的不妥操纵也会危及体系,比如向下面说的你不在的时分他人能够在你呆板上拷病毒,假如体系能在你不在的时分也能回绝这个家伙的登录妄图,那样贫苦岂不是少良多?因而在Java平安中心以外,供应了一个名为“Java认证与受权服务”(JavaAuthenticationandAuthorizationServices,JAAS)东东,专门用来处置对用户的认证和受权,这也就是所谓的“以用户为中央的受权模子”,说白了就是在“以代码为中央的受权模子”上再加一层,起首用户要取得会见权限,然后用户往利用代码,代码来实施真实的会见操纵。上面我次要是讲讲JAAS是怎样事情的。
2.懂得几个次要的API
JAAS的API基础上位于javax.security.auth包及其上司子包中,很简单找到的。
javax.security.auth.SubjectSubject表征体系中一个认证的用户,这个词时而被译为“主题”时而被觉得“主体”(上面我要谈到的Principal偶然候也被译为“主体”),不论它有几个马甲,归正你就能够当作是在Java中你这团体的影子,你对体系的会见就表现为Subject.doAs()或Subject.doAsPrivileged()办法。
java.security.PrincipalPrincipal代表用户的一种身份对象,一个用户的身份大概不但一个,他地点的组或所担当的脚色也是一种身份,“张翠山”能够说“铁划银钩”,能够说“张三丰的师傅”,能够说“张无忌他老爹”,我说“武当七侠”乃至“武当派”,固然也没错,这是一个组,呵呵。经由过程一次登录后,大概向Subject拔出一个或多个Principal,这时候候Subject才有实践意义,而不是一个空壳。
javax.security.auth.login.LoginContextLoginContext旨在供应一个开放的登录总接口,你只必要用从战略文件中获得的战略名,和上面先容的回调对象创立失掉一个LoginContext,再挪用一次login()办法便可完成登录,登录模块在这里是通明的。
javax.security.auth.spi.LoginModule登录模块完成了对用户的认证逻辑,它的感化是在登录设置文件中失掉表现,在前面的例子里我们会看到怎样编写一个登录设置文件和下面说过的战略文件。LoginModule接口包含五个次要的办法:initialize办法,初始化模块,保留以后Subject和一些参数。login办法,判别一次登录过程当中是不是认证经由过程。commit办法,是不是提交登录了局。咦,login不就好了吗?干嘛要来个提交呢?这是由于JAAS接纳的是相似于数据库事件处置的历程,将全体登录分为两阶段,只管你login乐成,但体系仍有权利依据你此次login的“位置”来决意事实要不要回收你的身份,只要经由过程commit,用户的Principal才会被真正增加到Subject傍边,哼哼,真凶险!这里所说的login的“位置”是指战略文件中登录模块的“把持标志”选项,有点相似于优先级的观点,由于登录一个体系的历程大概会经由不止一个登录模块,比如我们登录体系输出口令,但这个口令大概保留在一个数据库或LDAP目次中,会见这个数据源也必要经由认证,这就不止一个登录模块了吧?以是我们必要分清哪些认证历程是主要的,哪些又是主要的,体系对用户身份的吸收与否是对这些战略综合衡量的了局。abort办法:哎呀,下面注释得是否是太多了?我们再看看abort,还记得数据库事件处置的回退历程(rollback)吗?abort就有点像rollback,暗示体系其实不承受你的身份,之前做过的一切取消,现场又恢复到和登录前完整一样。logout办法:刊出历程,扫除外部形态,并删除Subject中全体的Principal。
javax.security.auth.callback.CallbackHandler回调对象是JAAS顶用以将交互历程和认证逻辑分别的一种机制,这也是切合OO和松懈耦合(looselycoupled是一个时兴辞汇^_^)精力的。JAAS已完成了一些经常使用的回调对象,包含获得用户名的NameCallback,获得口令的PasswordCallback,从终端取得输出文本的TextInputCallback,向终端收回文本动静的TextOutputCallback等等。我们所要做的仅仅是完成一个CallbackHandler接口,依据分歧的交互信息范例,把从终端失掉的信息填到响应的Callback中往就好了。前面的例子我是用了一个JoptionPane提醒文本框来输出用户名和口令的。
java.security.PrivilegedAction下面说了那末多登录像关的接口,该说说受权了,假如我们只谈写源代码,那末很复杂,只需完成一个PrivilegedAction接口,掩盖一个run()办法,把你想要做的事变一切放到这个run中就能够了。但我说的只是写源代码部分,受权方面用得较多的仍是在办理方面,比如怎样编写一个战略文件,上面我们就来看看JAAS登录和会见把持的一个完全流程。3.基础流程JAAS被称为是“可插拔的认证框架”(PluggableAuthenticationModule,PAMs),实在PAM也不是SUN的专利,Linux上就有这方面的完成,但PAM的确是较早用在了Solaris体系上。我们看看JAAS在认证和受权方面是怎样表现PAM头脑的:次要包含这么几个部分:用户的Principal(MyPrincipal.class)登录模块(MyLoginModule.class)回调对象(MyCallbackHandler.class)会见代码(MyAction.class)体系出口(JAASTest.class)资本(myfile.txt)战略设置文件(login.conf)登录设置文件(jaas.policy)启动剧本(JAASTest.bat)因为启动java的选项太长,以是写了一个shell,在把持台下运转JAASTest.bat,选项“-Djava.security.manager”指定启用平安办理器,实行的是JAASTest类的main线程,因为shell指定选项“-Djava.security.policy=jaas.policy”,该战略文件同意以后代码创立LoginContext,并受权举行别的一些操纵,它起首初始化一个LoginContext,选项“-Djava.security.auth.login.config=login.conf”指定了登录设置文件,以是在以后目次下找到文件login.conf,该文件中指定的登录战略称号为“JAASTest”,以是在LoginCotext中第一个参数也是“JAASTest”,同时利用我们自界说的回调对象MyCallbackHandler。创立LoginContext乐成,能够举行登录了,挪用LoginContext的login办法,该办法找到login.conf中的登录模块MyLoginModule(固然能够有多少个登录模块,这里我只用了一个),实行该模块的登录历程,MyLoginModule起首初始化:Loginmoduleinitializing...并利用LoginContext所付与它的回调对象MyCallbackHandler,该回调历程弹出两个图形对话框,请求输出用户名和口令,我们利用指定的用户名“user”和口令“letmepass”,断定今后分离传给以后的NameCallback和PasswordCallback,然后回到MyLoginModule的login历程,该历程从回调对象处失掉NameCallback和PasswordCallback,举行认证(这里仅仅是复杂的用户名和口令的对照),MyLoginModule:Authenticationpass!并决意是不是commit,因为在login.conf中界说该登录模块是required,以是是一个必需经由过程才干全体认证乐成的模块。MyLoginModule:Addanewprincipaltocurrentsubject.假如全体失掉认证经由过程,那末Subject就能够受权同意MyAction中的代码了,如语句Subject.doAs(…)所示,该代码的举措是读取以后目次下的myfile.txt文件,并将其内容打印到把持台,注重到在战略文件jaas.policy中付与MyPrincipal身份对myfile.txt的读取权限,以是我们乐成看到把持台下呈现Accesssuccessfully!Readingfile:==================================Why?Becausetheycare!Becausetheywanttoknowthetruth!Becausetheywanttheircountryback!Becauseitstillbelongstousaslongasthepeoplehavethegutstofightforwhattheybelievein!==================================这是我喜好的一部典范影片“JFK”中审查官Garrison热情的最初陈词中的一段,呵呵!以上历程我们能够用个图表来暗示:4.复杂的例子
以下流程中利用到的Java源代码和设置文件以下:
//MyPrincipal.javapackagecom.jungleford.auth;importjava.security.Principal;publicclassMyPrincipalimplementsPrincipal{//一个Principal的例子privateStringname;//Principal的名字publicMyPrincipal(Stringname){this.name=name;}publicStringgetName(){//获得Principal的名字returnthis.name;}publicbooleanequals(Objectprincipal){//判别两个Pincipal不异的根据if(principalinstanceofMyPrincipal)returnthis.name.equals(((MyPrincipal)principal).getName());elsereturnfalse;}publicStringtoString(){//Principal的暗示return"MyPrincipal:"+this.name;}publicinthashCode(){//断定本对象的散列值//用于有基于散列容器的场所,判别在散列容器中是不是是统一个对象。//假如对hashCode感乐趣,请拜见://http://www-900.ibm.com/developerWorks/cn/java/j-jtp05273/returnthis.name.hashCode();}}
//MyLoginModule.javapackagecom.jungleford.auth;importjava.util.*;importjava.io.IOException;importjava.security.Principal;importjavax.security.auth.*;importjavax.security.auth.callback.*;importjavax.security.auth.login.*;importjavax.security.auth.spi.*;publicclassMyLoginModuleimplementsLoginModule{//一个登录模块的例子privateSubjectsubject;//登录主体的表征privateCallbackHandlercbHandler;//回调对象,供应终端下猎取用户名、口令的界面privateMapsharedState;//用于缓存两头了局的共享区privateMapoptions;//用于保留某些登录模块所必要用到的一些设置选项privatebooleansucceeded=false;//一次login乐成的标记privatebooleancmtSucceeded=false;//全体登录乐成的提交标记privateStringusername;//获得用户名privatechar[]password;//获得口令privatePrincipalprincipal;//获得登录后的身份标记publicvoidinitialize(Subjectsubject,CallbackHandlercbHandler,MapsharedState,Mapoptions){//初始化历程System.out.println("Loginmoduleinitializing...");System.out.println();this.subject=subject;this.cbHandler=cbHandler;this.sharedState=sharedState;this.options=options;}publicbooleanlogin()throwsLoginException{//一次登录历程if(cbHandler==null)//还没有设置回调对象thrownewLoginException("Error:NoCallbackHandleravailable"+"togarnerauthenticationinformationfromtheuser");Callback[]cbs=newCallback[2];//仅利用用户名回协调口令回调cbs[0]=newNameCallback("Login:");cbs[1]=newPasswordCallback("Password:",false);try{cbHandler.handle(cbs);username=((NameCallback)cbs[0]).getName();char[]temp=((PasswordCallback)cbs[1]).getPassword();if(temp==null){//口令为空temp=newchar[0];}password=newchar[temp.length];System.arraycopy(temp,0,password,0,temp.length);((PasswordCallback)cbs[1]).clearPassword();//扫除内存中的口令陈迹}catch(IOExceptionioe){thrownewLoginException(ioe.toString());}catch(UnsupportedCallbackExceptionuce){thrownewLoginException("Error:"+uce.getCallback().toString()+"notavailabletogarnerauthenticationinformation"+"fromtheuser");}booleanusrCorrect=false;//用户名准确否?booleanpwdCorrect=false;//口令阃确否?if(username.equals("user"))//今朝仅同意用户名为user的登录usrCorrect=true;if(usrCorrect&&password.length==9&&password[0]==l&&password[1]==e&&password[2]==t&&password[3]==m&&password[4]==e&&password[5]==p&&password[6]==a&&password[7]==s&&password[8]==s)//user的口令指定为letmepass{System.out.println("MyLoginModule:Authenticationpass!");System.out.println();pwdCorrect=true;succeeded=true;returntrue;//一次登录乐成}else{System.out.println("MyLoginModule:Authenticationfailed!");System.out.println();succeeded=false;username=null;for(inti=0;i<password.length;i++)//扫除内存中的口令陈迹password[i]=;password=null;if(!usrCorrect){thrownewFailedLoginException("Usernameincorrect!");}else{thrownewFailedLoginException("Passwordincorrect!");}}}publicbooleancommit()throwsLoginException{//依据登录设置战略判别是不是全体登录乐成if(succeeded==false){returnfalse;}else{principal=newMyPrincipal(username);if(!subject.getPrincipals().contains(principal))subject.getPrincipals().add(principal);//把新的身份增加到subject中System.out.println("MyLoginModule:Addanewprincipaltocurrentsubject.");System.out.println();username=null;for(inti=0;i<password.length;i++)//扫除内存中的口令陈迹password[i]=;password=null;cmtSucceeded=true;returntrue;}}publicbooleanabort()throwsLoginException{//保持登录,将形态复位至登录前if(succeeded==false){returnfalse;}elseif(succeeded==true&&cmtSucceeded==false){succeeded=false;username=null;if(password!=null){for(inti=0;i<password.length;i++)//扫除内存中的口令陈迹password[i]=;password=null;}principal=null;}else{logout();}returntrue;}publicbooleanlogout()throwsLoginException{//刊出,并将形态复位至登录前subject.getPrincipals().remove(principal);succeeded=false;succeeded=cmtSucceeded;username=null;if(password!=null){for(inti=0;i<password.length;i++)//扫除内存中的口令陈迹password[i]=;password=null;}principal=null;returntrue;}}
//MyCallbackHandler.javapackagecom.jungleford.auth;importjava.io.IOException;importjavax.security.auth.callback.*;importjavax.swing.*;importjava.awt.*;importjava.awt.event.*;publicclassMyCallbackHandlerimplementsCallbackHandler{publicvoidhandle(Callback[]cbs)throwsIOException,UnsupportedCallbackException{Stringusername=JOptionPane.showInputDialog(null,"<html>Availablename:"+"<fontcolor="blue">user</font></html>","Enteryourname",JOptionPane.QUESTION_MESSAGE);Stringpassword=JOptionPane.showInputDialog(null,"<html>Availablepassword:"+"<fontcolor="blue">letmepass</font></html>","Enteryourpassword",JOptionPane.QUESTION_MESSAGE);for(inti=0;i<cbs.length;i++){if(cbs[i]instanceofTextOutputCallback){TextOutputCallbacktoc=(TextOutputCallback)cbs[i];switch(toc.getMessageType()){caseTextOutputCallback.INFORMATION:System.out.println(toc.getMessage());break;caseTextOutputCallback.ERROR:System.out.println("Error:"+toc.getMessage());break;caseTextOutputCallback.WARNING:System.out.println("Warning:"+toc.getMessage());break;default:thrownewIOException("Unsupportedmessagetype:"+toc.getMessageType());}}elseif(cbs[i]instanceofNameCallback){//prompttheuserforausernameNameCallbacknc=(NameCallback)cbs[i];//System.err.print(nc.getPrompt());//System.err.flush();nc.setName(username);}elseif(cbs[i]instanceofPasswordCallback){//prompttheuserforsensitiveinformationPasswordCallbackpc=(PasswordCallback)cbs[i];//System.err.print(pc.getPrompt());//System.err.flush();pc.setPassword(password.toCharArray());}else{thrownewUnsupportedCallbackException(cbs[i],"UnrecognizedCallback");}}}}
//MyAction.javapackagecom.jungleford.auth;importjava.io.*;importjava.security.*;publicclassMyActionimplementsPrivilegedAction{//对资本的受权会见举措publicObjectrun(){//run办法是必需overriding的//这里我们假定会见举措是读取以后目次下myfile.txt文件的内容Filefile=newFile("myfile.txt");Stringcontent="";try{BufferedReaderreader=newBufferedReader(newFileReader(file));Stringline=reader.readLine();while(line!=null){content+=line+"
";line=reader.readLine();}}catch(Exceptione){System.err.println("Error:Readingfilefailed!");System.err.println();e.printStackTrace();}returncontent;}}
//JAASTest.javapackagecom.jungleford.auth;importjavax.security.auth.Subject;importjavax.security.auth.login.LoginContext;publicclassJAASTest{//测试我们JAAS登录和受权的shellpublicstaticvoidmain(String[]args){LoginContextlc=null;try{//创立context,利用自界说的回调对象,战略名为JAASTest//复杂起见,仅利用一个MyLoginModule模块lc=newLoginContext("JAASTest",newMyCallbackHandler());}catch(Exceptione){System.err.println("Error:Creatinglogincontextfailed!");System.err.println();e.printStackTrace();System.exit(-1);}try{//全体登录lc.login();}catch(Exceptione){System.err.println("Error:Loginfailed!");System.err.println();e.printStackTrace();System.exit(-1);}//取得受权会见Objectobject=Subject.doAs(lc.getSubject(),newMyAction());System.out.println("Accesssuccessfully!Readingfile:");System.out.println("==================================");System.out.println(object);System.out.println("==================================");System.exit(0);}}
//login.conf
JAASTest{com.jungleford.auth.MyLoginModulerequired;};
//jaas.policy
grant{permissionjavax.security.auth.AuthPermission"createLoginContext";permissionjavax.security.auth.AuthPermission"doAs";permissionjavax.security.auth.AuthPermission"modifyPrincipals";permissionjavax.security.auth.AuthPermission"getSubject";};grantprincipalcom.jungleford.auth.MyPrincipal"guest"{permissionjava.io.FilePermission"myfile.txt","read";};
//JAASTest.bat
java-Djava.security.manager-Djava.security.auth.login.config=login.conf-Djava.security.policy=jaas.policycom.jungleford.auth.JAASTest
//myfile.txt
Why?Becausetheycare!Becausetheywanttoknowthetruth!Becausetheywanttheircountryback!Becauseitstillbelongstousaslongasthepeoplehavethegutstofightforwhattheybelievein!
参考材料
参考材料
JavaSecurityArchitectureJava受权内情Java平安性第二部分:认证与受权JavaSecurity,2ndEdition,byScottOaksJ2EESecurity,byPankajKumar
//MyLoginModule.javapackagecom.jungleford.auth;importjava.util.*;importjava.io.IOException;importjava.security.Principal;importjavax.security.auth.*;importjavax.security.auth.callback.*;importjavax.security.auth.login.*;importjavax.security.auth.spi.*;publicclassMyLoginModuleimplementsLoginModule{//一个登录模块的例子privateSubjectsubject;//登录主体的表征privateCallbackHandlercbHandler;//回调对象,供应终端下猎取用户名、口令的界面privateMapsharedState;//用于缓存两头了局的共享区privateMapoptions;//用于保留某些登录模块所必要用到的一些设置选项privatebooleansucceeded=false;//一次login乐成的标记privatebooleancmtSucceeded=false;//全体登录乐成的提交标记privateStringusername;//获得用户名privatechar[]password;//获得口令privatePrincipalprincipal;//获得登录后的身份标记publicvoidinitialize(Subjectsubject,CallbackHandlercbHandler,MapsharedState,Mapoptions){//初始化历程System.out.println("Loginmoduleinitializing...");System.out.println();this.subject=subject;this.cbHandler=cbHandler;this.sharedState=sharedState;this.options=options;}publicbooleanlogin()throwsLoginException{//一次登录历程if(cbHandler==null)//还没有设置回调对象thrownewLoginException("Error:NoCallbackHandleravailable"+"togarnerauthenticationinformationfromtheuser");Callback[]cbs=newCallback[2];//仅利用用户名回协调口令回调cbs[0]=newNameCallback("Login:");cbs[1]=newPasswordCallback("Password:",false);try{cbHandler.handle(cbs);username=((NameCallback)cbs[0]).getName();char[]temp=((PasswordCallback)cbs[1]).getPassword();if(temp==null){//口令为空temp=newchar[0];}password=newchar[temp.length];System.arraycopy(temp,0,password,0,temp.length);((PasswordCallback)cbs[1]).clearPassword();//扫除内存中的口令陈迹}catch(IOExceptionioe){thrownewLoginException(ioe.toString());}catch(UnsupportedCallbackExceptionuce){thrownewLoginException("Error:"+uce.getCallback().toString()+"notavailabletogarnerauthenticationinformation"+"fromtheuser");}booleanusrCorrect=false;//用户名准确否?booleanpwdCorrect=false;//口令阃确否?if(username.equals("user"))//今朝仅同意用户名为user的登录usrCorrect=true;if(usrCorrect&&password.length==9&&password[0]==l&&password[1]==e&&password[2]==t&&password[3]==m&&password[4]==e&&password[5]==p&&password[6]==a&&password[7]==s&&password[8]==s)//user的口令指定为letmepass{System.out.println("MyLoginModule:Authenticationpass!");System.out.println();pwdCorrect=true;succeeded=true;returntrue;//一次登录乐成}else{System.out.println("MyLoginModule:Authenticationfailed!");System.out.println();succeeded=false;username=null;for(inti=0;i<password.length;i++)//扫除内存中的口令陈迹password[i]=;password=null;if(!usrCorrect){thrownewFailedLoginException("Usernameincorrect!");}else{thrownewFailedLoginException("Passwordincorrect!");}}}publicbooleancommit()throwsLoginException{//依据登录设置战略判别是不是全体登录乐成if(succeeded==false){returnfalse;}else{principal=newMyPrincipal(username);if(!subject.getPrincipals().contains(principal))subject.getPrincipals().add(principal);//把新的身份增加到subject中System.out.println("MyLoginModule:Addanewprincipaltocurrentsubject.");System.out.println();username=null;for(inti=0;i<password.length;i++)//扫除内存中的口令陈迹password[i]=;password=null;cmtSucceeded=true;returntrue;}}publicbooleanabort()throwsLoginException{//保持登录,将形态复位至登录前if(succeeded==false){returnfalse;}elseif(succeeded==true&&cmtSucceeded==false){succeeded=false;username=null;if(password!=null){for(inti=0;i<password.length;i++)//扫除内存中的口令陈迹password[i]=;password=null;}principal=null;}else{logout();}returntrue;}publicbooleanlogout()throwsLoginException{//刊出,并将形态复位至登录前subject.getPrincipals().remove(principal);succeeded=false;succeeded=cmtSucceeded;username=null;if(password!=null){for(inti=0;i<password.length;i++)//扫除内存中的口令陈迹password[i]=;password=null;}principal=null;returntrue;}}
//MyCallbackHandler.javapackagecom.jungleford.auth;importjava.io.IOException;importjavax.security.auth.callback.*;importjavax.swing.*;importjava.awt.*;importjava.awt.event.*;publicclassMyCallbackHandlerimplementsCallbackHandler{publicvoidhandle(Callback[]cbs)throwsIOException,UnsupportedCallbackException{Stringusername=JOptionPane.showInputDialog(null,"<html>Availablename:"+"<fontcolor="blue">user</font></html>","Enteryourname",JOptionPane.QUESTION_MESSAGE);Stringpassword=JOptionPane.showInputDialog(null,"<html>Availablepassword:"+"<fontcolor="blue">letmepass</font></html>","Enteryourpassword",JOptionPane.QUESTION_MESSAGE);for(inti=0;i<cbs.length;i++){if(cbs[i]instanceofTextOutputCallback){TextOutputCallbacktoc=(TextOutputCallback)cbs[i];switch(toc.getMessageType()){caseTextOutputCallback.INFORMATION:System.out.println(toc.getMessage());break;caseTextOutputCallback.ERROR:System.out.println("Error:"+toc.getMessage());break;caseTextOutputCallback.WARNING:System.out.println("Warning:"+toc.getMessage());break;default:thrownewIOException("Unsupportedmessagetype:"+toc.getMessageType());}}elseif(cbs[i]instanceofNameCallback){//prompttheuserforausernameNameCallbacknc=(NameCallback)cbs[i];//System.err.print(nc.getPrompt());//System.err.flush();nc.setName(username);}elseif(cbs[i]instanceofPasswordCallback){//prompttheuserforsensitiveinformationPasswordCallbackpc=(PasswordCallback)cbs[i];//System.err.print(pc.getPrompt());//System.err.flush();pc.setPassword(password.toCharArray());}else{thrownewUnsupportedCallbackException(cbs[i],"UnrecognizedCallback");}}}}
//MyAction.javapackagecom.jungleford.auth;importjava.io.*;importjava.security.*;publicclassMyActionimplementsPrivilegedAction{//对资本的受权会见举措publicObjectrun(){//run办法是必需overriding的//这里我们假定会见举措是读取以后目次下myfile.txt文件的内容Filefile=newFile("myfile.txt");Stringcontent="";try{BufferedReaderreader=newBufferedReader(newFileReader(file));Stringline=reader.readLine();while(line!=null){content+=line+"
";line=reader.readLine();}}catch(Exceptione){System.err.println("Error:Readingfilefailed!");System.err.println();e.printStackTrace();}returncontent;}}
//JAASTest.javapackagecom.jungleford.auth;importjavax.security.auth.Subject;importjavax.security.auth.login.LoginContext;publicclassJAASTest{//测试我们JAAS登录和受权的shellpublicstaticvoidmain(String[]args){LoginContextlc=null;try{//创立context,利用自界说的回调对象,战略名为JAASTest//复杂起见,仅利用一个MyLoginModule模块lc=newLoginContext("JAASTest",newMyCallbackHandler());}catch(Exceptione){System.err.println("Error:Creatinglogincontextfailed!");System.err.println();e.printStackTrace();System.exit(-1);}try{//全体登录lc.login();}catch(Exceptione){System.err.println("Error:Loginfailed!");System.err.println();e.printStackTrace();System.exit(-1);}//取得受权会见Objectobject=Subject.doAs(lc.getSubject(),newMyAction());System.out.println("Accesssuccessfully!Readingfile:");System.out.println("==================================");System.out.println(object);System.out.println("==================================");System.exit(0);}}
//login.conf
JAASTest{com.jungleford.auth.MyLoginModulerequired;};
//jaas.policy
grant{permissionjavax.security.auth.AuthPermission"createLoginContext";permissionjavax.security.auth.AuthPermission"doAs";permissionjavax.security.auth.AuthPermission"modifyPrincipals";permissionjavax.security.auth.AuthPermission"getSubject";};grantprincipalcom.jungleford.auth.MyPrincipal"guest"{permissionjava.io.FilePermission"myfile.txt","read";};
//JAASTest.bat
java-Djava.security.manager-Djava.security.auth.login.config=login.conf-Djava.security.policy=jaas.policycom.jungleford.auth.JAASTest
//myfile.txt
Why?Becausetheycare!Becausetheywanttoknowthetruth!Becausetheywanttheircountryback!Becauseitstillbelongstousaslongasthepeoplehavethegutstofightforwhattheybelievein!
参考材料
参考材料
JavaSecurityArchitectureJava受权内情Java平安性第二部分:认证与受权JavaSecurity,2ndEdition,byScottOaksJ2EESecurity,byPankajKumarJavaSecurityArchitectureJava受权内情Java平安性第二部分:认证与受权JavaSecurity,2ndEdition,byScottOaksJ2EESecurity,byPankajKumar
首先第一点:jsp,servlet,javabean这些最基本的,嘿嘿,就算你是高手的话,在大行的企业级应用的话还是需要框架的,一个好的框架确实能构解决许多问题。 |
|