FluorineFx:认证与授权

来源:互联网 发布:淘宝店铺售后服务 编辑:程序博客网 时间:2024/05/17 00:00

FluorineFx:认证与授权

对认证与授权没啥概念的新同学,建议先看下 .net中的认证(authentication)与授权(authorization),然后再继续。

 

Flash/Flex在通过FluorineFx调用.Net中的方法时,同样也会遇到认证与授权问题,即:

 “是否随便一个阿猫阿狗都能来调用我的方法?”或者可以理解为:“调用我的方法前是否需要登录?” 这就是认证

“门卫放进来后,是不是不管什么身份的人,都能来拿东西?”或者可以理解为:“登录后的用户,具备何种资格的人才能调用方法?” 这就是授权

 

步骤:

1、先创建自己的LoginCommand类(相当于门卫,用于把关):DemoLoginCommand

01using System.Collections;
02using System.Security.Principal;
03using FluorineFx.Security;
04 
05namespace _04_Authentication
06{
07    publicclassDemoLoginCommand:GenericLoginCommand
08    {
09        publicoverrideIPrincipal DoAuthentication(stringusername, Hashtable credentials)
10        {
11            stringpassword = credentials["password"]asstring;          
12            if(username.Length > 0)//当然:这里只是演示,实际应用中可从数据库中检验用户名和密码
13            {
14                GenericIdentity identity =newGenericIdentity(username);
15                //下面的代码,授予登录用户:"admin"角色,仍然只是演示,实际应用中,可以根据用户名到数据库里查询对应的角色
16                GenericPrincipal principal =newGenericPrincipal(identity,newstring[] {"admin"});
17 
18                returnprincipal;
19            }
20            else//检验不通过的处理
21            {
22                returnnull;
23            }
24        }
25    }
26}

2、再创建一个不需要认证就能随便调用的远程服务 DemoLoginService

01using System;
02using System.Collections.Generic;
03using System.Linq;
04using System.Web;
05using FluorineFx;
06 
07namespace _04_Authentication
08{
09    [RemotingService]
10    publicclassDemoLoginService
11    {
12        //其实这个方法随便起什么名字都行,只要在flash中调用时跟这里一致就行(可以理解为方法占位符),但是通常为了有意义,命名为Login
13        publicboolLogin()
14        {
15            //这个返回值,其实返回true或false都无所谓,重点不在这里
16            returntrue;
17        }
18 
19        //同样,这里方法的名字其实也可以随便起
20        publicboolLogout()
21        {
22            newDemoLoginCommand().Logout(null);//这一行才是关键,相当于把"认证信息"清空了
23            returntrue;//明白了上一行后,其实也应该能想到:这里返回true或flase其实都不重要
24        }
25    }
26}

3、为了对比,再来创建一个需要认证的远程服务:DemoSecureService

01using System;
02using System.Collections.Generic;
03using System.Linq;
04using System.Web;
05using FluorineFx;
06 
07namespace _04_Authentication
08{
09    [RemotingService]
10    publicclassDemoSecureService
11    {        
12        //太简单了,不作解释了
13        publicstringHelloWorld()
14        {
15            return"从服务端返回的安全数据.";
16        }
17    }
18}

等一下,提个问题:比较这个服务跟刚才创建的服务,除了里面的方法名称(及相关的方法处理逻辑)不同,本质上没区别吧? 凭啥说调用这个服务就需要认证,而刚才那个服务就能随便调用?

很好,希望大家带着这个问题继续,后面会揭晓。

先打个岔:回想一下asp.net中后台目录权限的处理,我们可以在web.config 中通过配置来决定某个目录是否可访问

1<locationpath="admin">
2    <system.web>
3        <authorization>
4            <denyusers="?"/>
5            <denyroles="买家"/>
6            <denyroles="卖家"/>
7        </authorization>
8    </system.web>
9</location>

这段配置的意思就是 /admin目录,匿名用户无法访问(即要求登录),同时"买家","卖家"二种角色被拒绝了(即:就算你登录了,只要你是"买家"或"卖家"角色,同样也访问不了)

FluorineFx中,同样也是用配置来实现权限访问的:

先看remoting-config.xml的配置

01<?xmlversion="1.0"encoding="UTF-8"?>
02<serviceid="remoting-service"
03    class="flex.messaging.services.RemotingService"
04    messageTypes="flex.messaging.messages.RemotingMessage">
05 
06 
07  <adapters>
08    <adapter-definitionid="dotnet"class="FluorineFx.Remoting.RemotingAdapter"default="true"/>
09  </adapters>
10 
11  <default-channels>
12    <channelref="my-amf"/>
13  </default-channels>
14 
15 
16 
17  <destinationid="fluorine">
18    <properties>
19      <!--这里表示所有源(文件)包括在内-->
20      <source>*</source>
21    </properties>
22    <security>
23      <!--这里表明访问上面source中定义的服务时,必须满足"privileged-users"的安全限制-->
24      <security-constraintref="privileged-users"/>
25    </security>
26  </destination>
27 
28 
29  <destinationid="login">
30    <properties>
31      <source>_04_Authentication.DemoLoginService</source>
32      <!--注意这里没有<security />节点,即_04_Authentication.DemoLoginService的访问没有安全限制,也就是可随便调用-->
33    </properties>
34  </destination>
35 
36</service>

关键地方已经注释了,这个配置就表明了_04_Authentication.DemoLoginService不需要登录就能调用,而其它服务调用时要受到"privileged-users"的限制,那么这个限制到底如何描述的呢?

services-config.xml配置

01<?xmlversion="1.0"encoding="utf-8"?>
02<services-config>
03  <services>
04    <service-includefile-path="remoting-config.xml"/>
05  </services>
06 
07 
08  <security>
09    <!--这里跟前面的"privileged-users"对应上了-->
10    <security-constraintid="privileged-users">
11      <!--表明认证方法为开发人员自定义-->
12      <auth-method>Custom</auth-method>
13      <!--调用该限制相关的服务,必须是admin或user角色-->
14      <roles>
15        <role>admin</role>
16        <role>user</role>
17      </roles>
18    </security-constraint>
19    <!--这里指明了验证登录时,由谁来把关,即DemoLoginCommand-->
20    <login-commandclass="_04_Authentication.DemoLoginCommand"server="asp.net"/>
21  </security>
22 
23  <channels>
24    <channel-definitionid="my-amf"class="mx.messaging.channels.AMFChannel">
25      <endpointuri="http://{server.name}:{server.port}/{context.root}/Gateway.aspx"class="flex.messaging.endpoints.AMFEndpoint"/>
26    </channel-definition>
27    <properties>
28      <!-- <legacy-collection>true</legacy-collection> -->
29    </properties>
30  </channels>
31</services-config>

同样:重点地方已经加了注释。

另外一个重要配置:fluorineFx说到底是宿主在asp.net iis环境中的,所以它的认证票据同样是保存在cookie中的,web.config的表单认证方式要设置为Forms,即

view sourceprint?
01<?xmlversion="1.0"?>
02<configuration>
03  <system.web>
04    <compilationdebug="true"targetFramework="4.0"/>
05 
06    <httpModules>
07      <addname="FluorineGateway"type="FluorineFx.FluorineGateway, FluorineFx"/>
08    </httpModules>
09 
10     <!--这里要指定为Forms认证方式-->
11    <authenticationmode="Forms"></authentication>
12     
13  </system.web>
14</configuration>

ok,服务端就全部完成了,再来看Flash端的调用:

UI界面:

 

先讲下我们要做什么:

a、点击“登录”或“注销”时,调用不需要登录的DemoLoginService

b、点击"远程调用"时,调用需要认证的DemoSecureService

预测一下结果:

点击“登录”前,如果直接点击“远程调用”,应该会调用失败(因此此时尚未登录认证)

如果先点击“登录”后,再点击“远程调用”,因为这时已经登录认证过了,所以应该成功

完整flash代码:

001package
002{
003    importflash.display.Sprite;
004    importflash.net.ObjectEncoding;
005    importorg.bytearray.remoting.Service;
006    importorg.bytearray.remoting.PendingCall;
007    importorg.bytearray.remoting.events.ResultEvent;
008    importorg.bytearray.remoting.events.FaultEvent;
009    importfl.controls.TextInput;
010    importflash.text.TextField;
011    importfl.controls.TextArea;
012    importfl.controls.Button;
013    importflash.events.MouseEvent;
014 
015 
016 
017    publicclassLoginDemo extendsSprite
018    {
019        privatevar_txtUserName:TextInput;
020        privatevar_txtPassWord:TextInput;
021        privatevar_txtResult:TextArea;
022        privatevar_btnLogin:Button;
023        privatevar_btnLogOut:Button;
024        privatevar_btnCall:Button;
025 
026        privatevar_gatewayUrl:String="";
027        privatevar_service:Service;      
028        privatevar_callService:Service;
029        privatevar_rpc:PendingCall;
030         
031 
032        publicfunctionLoginDemo()
033        {
034 
035            this._txtUserName = txtUserName;
036            this._txtPassWord = txtPassword;
037            this._txtResult = txtResult;
038            this._btnCall = btnCall;
039            this._btnLogin = btnLogin;
040            this._btnLogOut = btnLogout;
041 
042            this._txtUserName.text ="菩提树下的杨过";
043            this._txtPassWord.displayAsPassword =true;
044            this._txtPassWord.text ="123456";
045 
046 
047            if(root.loaderInfo.parameters.remotingGatewayPath !=null)
048            {
049                _gatewayUrl = root.loaderInfo.parameters.remotingGatewayPath +"/Gateway.aspx";
050            }
051            else
052            {
053                _gatewayUrl ="http://localhost:22892/Gateway.aspx";
054 
055            }
056             
057 
058            this._btnLogin.addEventListener(MouseEvent.CLICK,btnLogin_Click);
059            this._btnLogOut.addEventListener(MouseEvent.CLICK,btnLogout_Click);
060            this._btnCall.addEventListener(MouseEvent.CLICK,btnCall_Click);
061 
062 
063        }
064         
065        //登录
066        privatefunctionbtnLogin_Click(e:MouseEvent):void
067        {
068            _service =newService("_04_Authentication.DemoLoginService",_gatewayUrl,ObjectEncoding.AMF3);
069            //这一行是关键,用于将用户名、密码发送到DemoLoginCommand
070            _service.setRemoteCredentials(this._txtUserName.text,this._txtPassWord.text);                     
071            _rpc = _service.Login();
072            _rpc.addEventListener( ResultEvent.RESULT, loginSuccess );
073            _rpc.addEventListener( FaultEvent.FAULT, loginFailure );
074 
075        }
076 
077        privatefunctionloginSuccess( pEvt:ResultEvent ):void
078        {
079            this._txtResult.text ="登录成功!";
080        }
081 
082 
083 
084        privatefunctionloginFailure( pEvt:FaultEvent ):void
085        {
086            this._txtResult.text ="登录失败,原因:"+ pEvt.fault.description;
087        }
088         
089        //注销
090        privatefunctionbtnLogout_Click(e:MouseEvent):void
091        {
092            _service =newService("_04_Authentication.DemoLoginService",_gatewayUrl,ObjectEncoding.AMF3);
093            _rpc = _service.Logout();
094            _rpc.addEventListener( ResultEvent.RESULT, logoutSuccess );
095            _rpc.addEventListener( FaultEvent.FAULT, logoutFailure );
096 
097        }
098         
099         
100        privatefunctionlogoutSuccess( pEvt:ResultEvent ):void
101        {
102            this._txtResult.text ="注销成功!";
103        }
104 
105 
106 
107        privatefunctionlogoutFailure( pEvt:FaultEvent ):void
108        {
109            this._txtResult.text ="注销失败,原因:"+ pEvt.fault.description;
110        }
111         
112        //远程调用需要认证的服务
113        privatefunctionbtnCall_Click(e:MouseEvent):void
114        {
115            _callService =newService("_04_Authentication.DemoSecureService",_gatewayUrl,ObjectEncoding.AMF3);
116            _rpc = _callService.HelloWorld();
117            _rpc.addEventListener( ResultEvent.RESULT, callSuccess );
118            _rpc.addEventListener( FaultEvent.FAULT, callFailure );
119 
120        }
121         
122         
123        privatefunctioncallSuccess( pEvt:ResultEvent ):void
124        {
125            this._txtResult.text ="调用成功:"+ pEvt.result;
126        }
127 
128 
129 
130        privatefunctioncallFailure( pEvt:FaultEvent ):void
131        {
132            this._txtResult.text ="调用失败,原因:"+ pEvt.fault.description;
133        }
134    }
135}

测试运行的截图:

这是一上来就直接点击"远程调用"的结果,注意右侧的大文本框:Requested access is not allowed 即访问不允许,说明这个服务是需要认证才能调用的。

如果点击“登录”后,再点击"远程调用",这回成功了,说明认证起作用了。

 

最后再啰嗦一下:前面提到了FluorineFx的认证票据跟asp.net一样,是保存在Cookie的,所以如果您把swf嵌入到网页上,在flash中点击登录后,如果在其它aspx页面上用

01<% if(!User.Identity.IsAuthenticated)
02      {
03          Response.Write("<h5>尚未登录!</h5>");
04      }
05      else
06      {
07          Response.Write("<h5><span style='color:red'>"+ User.Identity.Name +"</span>已经登录!</h5>");
08 
09           
10      }
11    %>

同样也能检测出用户的登录状态!(前提是不要关闭刚才那个嵌入swf的页面)

 

唯一遗憾的是:FluorineFx生成的Cookie认证票据中,并未包含Roles角色信息,所以在AspX页面上无法用IsInRole来判断当前用户的角色(我跟踪了一下,fluorineFx在Cookie中仅保存了用户名、密码以及一些唯一性标识,官方提供的认证演示中虽然有用IsInRole来判断,但其实是没用的)。

 

当然这个问题,您可以修改FluorineFx的源码来解决,这点工作就留给大家了。 

 

不过令人高兴的是,反过来却可以!即:如果在asp.net上登录了,认证和授权信息在flash里能识别,通常情况下,这已经能满足绝大多数需要了。

 

示例源代码下载: http://cid-2959920b8267aaca.office.live.com/self.aspx/Flash/FluorineFx^_Demo^_04.rar

作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文连接:http://www.cnblogs.com/yjmyzz/archive/2010/08/30/1812956.html

原创粉丝点击