FluorineFx:认证与授权

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

 

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

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

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

 

步骤:

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

using System.Collections;
using System.Security.Principal;
using FluorineFx.Security;

namespace _04_Authentication
{
    public class DemoLoginCommand:GenericLoginCommand
    {
        public override IPrincipal DoAuthentication(string username, Hashtable credentials)
        {
            string password = credentials["password"] as string;
            if (username.Length > 0)//当然:这里只是演示,实际应用中可从数据库中检验用户名和密码
            {
                GenericIdentity identity = new GenericIdentity(username);
                //下面的代码,授予登录用户:"admin"角色,仍然只是演示,实际应用中,可以根据用户名到数据库里查询对应的角色
                GenericPrincipal principal = new GenericPrincipal(identity, new string[] { "admin"});

                return principal;
            }
            else //检验不通过的处理
            {
                return null;
            }
        }
    }
}

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using FluorineFx;

namespace _04_Authentication
{
    [RemotingService]
    public class DemoLoginService
    {
        //其实这个方法随便起什么名字都行,只要在flash中调用时跟这里一致就行(可以理解为方法占位符),但是通常为了有意义,命名为Login
        public bool Login()
        {
            //这个返回值,其实返回true或false都无所谓,重点不在这里
            return true;
        }

        //同样,这里方法的名字其实也可以随便起
        public bool Logout()
        {
            new DemoLoginCommand().Logout(null); //这一行才是关键,相当于把"认证信息"清空了
            return true;//明白了上一行后,其实也应该能想到:这里返回true或flase其实都不重要
        }
    }
}

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using FluorineFx;

namespace _04_Authentication
{
    [RemotingService]
    public class DemoSecureService
    {
        //太简单了,不作解释了
        public string HelloWorld()
        {
            return "从服务端返回的安全数据.";
        }
    }
}

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

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

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

<location path="admin">
	<system.web>
		<authorization>
			<deny users="?" />
			<deny roles="买家" />
			<deny roles="卖家" />
		</authorization>
	</system.web>
</location>

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

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

先看remoting-config.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service"
    class="flex.messaging.services.RemotingService"
    messageTypes="flex.messaging.messages.RemotingMessage">

  <adapters>
    <adapter-definition id="dotnet" class="FluorineFx.Remoting.RemotingAdapter" default="true"/>
  </adapters>

  <default-channels>
    <channel ref="my-amf"/>
  </default-channels>

  <destination id="fluorine">
    <properties>
      <!--这里表示所有源(文件)包括在内-->
      <source>*</source>
    </properties>
    <security>
      <!--这里表明访问上面source中定义的服务时,必须满足"privileged-users"的安全限制-->
      <security-constraint ref="privileged-users"/>
    </security>
  </destination>

  <destination id="login">
    <properties>
      <source>_04_Authentication.DemoLoginService</source>
      <!--注意这里没有<security />节点,即_04_Authentication.DemoLoginService的访问没有安全限制,也就是可随便调用-->
    </properties>
  </destination>

</service>

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

services-config.xml配置

<?xml version="1.0" encoding="utf-8" ?>
<services-config>
  <services>
    <service-include file-path="remoting-config.xml" />
  </services>

  <security>
    <!--这里跟前面的"privileged-users"对应上了-->
    <security-constraint id="privileged-users">
      <!--表明认证方法为开发人员自定义-->
      <auth-method>Custom</auth-method>
      <!--调用该限制相关的服务,必须是admin或user角色-->
      <roles>
        <role>admin</role>
        <role>user</role>
      </roles>
    </security-constraint>
    <!--这里指明了验证登录时,由谁来把关,即DemoLoginCommand-->
    <login-command class="_04_Authentication.DemoLoginCommand" server="asp.net"/>
  </security>

  <channels>
    <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
      <endpoint uri="http://{server.name}:{server.port}/{context.root}/Gateway.aspx" class="flex.messaging.endpoints.AMFEndpoint"/>
    </channel-definition>
    <properties>
      <!-- <legacy-collection>true</legacy-collection> -->
    </properties>
  </channels>
</services-config>

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

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

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />

    <httpModules>
      <add name="FluorineGateway" type="FluorineFx.FluorineGateway, FluorineFx"/>
    </httpModules>

     <!--这里要指定为Forms认证方式-->
    <authentication mode="Forms"></authentication>

  </system.web>
</configuration>

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

UI界面:

 

先讲下我们要做什么:

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

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

预测一下结果:

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

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

完整flash代码:

package
{
	import flash.display.Sprite;
	import flash.net.ObjectEncoding;
	import org.bytearray.remoting.Service;
	import org.bytearray.remoting.PendingCall;
	import org.bytearray.remoting.events.ResultEvent;
	import org.bytearray.remoting.events.FaultEvent;
	import fl.controls.TextInput;
	import flash.text.TextField;
	import fl.controls.TextArea;
	import fl.controls.Button;
	import flash.events.MouseEvent;

	public class LoginDemo extends Sprite
	{
		private var _txtUserName:TextInput;
		private var _txtPassWord:TextInput;
		private var _txtResult:TextArea;
		private var _btnLogin:Button;
		private var _btnLogOut:Button;
		private var _btnCall:Button;

		private var _gatewayUrl:String = "";
		private var _service:Service;
		private var _callService:Service;
		private var _rpc:PendingCall;

		public function LoginDemo()
		{

			this._txtUserName = txtUserName;
			this._txtPassWord = txtPassword;
			this._txtResult = txtResult;
			this._btnCall = btnCall;
			this._btnLogin = btnLogin;
			this._btnLogOut = btnLogout;

			this._txtUserName.text = "菩提树下的杨过";
			this._txtPassWord.displayAsPassword = true;
			this._txtPassWord.text = "123456";

			if (root.loaderInfo.parameters.remotingGatewayPath != null)
			{
				_gatewayUrl = root.loaderInfo.parameters.remotingGatewayPath + "/Gateway.aspx";
			}
			else
			{
				_gatewayUrl = "http://localhost:22892/Gateway.aspx";

			}

			this._btnLogin.addEventListener(MouseEvent.CLICK,btnLogin_Click);
			this._btnLogOut.addEventListener(MouseEvent.CLICK,btnLogout_Click);
			this._btnCall.addEventListener(MouseEvent.CLICK,btnCall_Click);

		}

		//登录
		private function btnLogin_Click(e:MouseEvent):void
		{
			_service = new Service("_04_Authentication.DemoLoginService",_gatewayUrl,ObjectEncoding.AMF3);
			//这一行是关键,用于将用户名、密码发送到DemoLoginCommand
			_service.setRemoteCredentials(this._txtUserName.text, this._txtPassWord.text);
			_rpc = _service.Login();
			_rpc.addEventListener( ResultEvent.RESULT, loginSuccess );
			_rpc.addEventListener( FaultEvent.FAULT, loginFailure );

		}

		private function loginSuccess( pEvt:ResultEvent ):void
		{
			this._txtResult.text = "登录成功!";
		}

		private function loginFailure( pEvt:FaultEvent ):void
		{
			this._txtResult.text = "登录失败,原因:" + pEvt.fault.description;
		}

		//注销
		private function btnLogout_Click(e:MouseEvent):void
		{
			_service = new Service("_04_Authentication.DemoLoginService",_gatewayUrl,ObjectEncoding.AMF3);
			_rpc = _service.Logout();
			_rpc.addEventListener( ResultEvent.RESULT, logoutSuccess );
			_rpc.addEventListener( FaultEvent.FAULT, logoutFailure );

		}

		private function logoutSuccess( pEvt:ResultEvent ):void
		{
			this._txtResult.text = "注销成功!";
		}

		private function logoutFailure( pEvt:FaultEvent ):void
		{
			this._txtResult.text = "注销失败,原因:" + pEvt.fault.description;
		}

		//远程调用需要认证的服务
		private function btnCall_Click(e:MouseEvent):void
		{
			_callService = new Service("_04_Authentication.DemoSecureService",_gatewayUrl,ObjectEncoding.AMF3);
			_rpc = _callService.HelloWorld();
			_rpc.addEventListener( ResultEvent.RESULT, callSuccess );
			_rpc.addEventListener( FaultEvent.FAULT, callFailure );

		}

		private function callSuccess( pEvt:ResultEvent ):void
		{
			this._txtResult.text = "调用成功:" + pEvt.result;
		}

		private function callFailure( pEvt:FaultEvent ):void
		{
			this._txtResult.text = "调用失败,原因:" + pEvt.fault.description;
		}
	}
}

测试运行的截图:

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

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

 

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

 <% if (!User.Identity.IsAuthenticated)
       {
           Response.Write("<h5>尚未登录!</h5>");
       }
       else
       {
           Response.Write("<h5><span style='color:red'>" + User.Identity.Name + "</span>已经登录!</h5>");

       }
     %>

同样也能检测出用户的登录状态!(前提是不要关闭刚才那个嵌入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

时间: 2024-07-29 05:02:16

FluorineFx:认证与授权的相关文章

跪求spring security中认证和授权的关系

问题描述 跪求spring security中认证和授权的关系 是认证里边包含授权,还是认证和授权是一体的,他们的顺序是怎么样的?过程是怎么样的,蒙了.... 解决方案 http://sishuok.com/forum/blogPost/list/4313.html 解决方案二: Spring security认证与授权(二)

sso-关于SSO认证 和授权的问题

问题描述 关于SSO认证 和授权的问题 公司有4套系统,现在每个系统都有独立的用户管理模块,和用户权限模块. 这样用户使用起来就不是很方便,所以公司希望通过SSO单点登录来解决用户账户管理的复杂度. 本人想到的方案是,建立一套Standalone 的SSO server ,用户访问各子系统时,跳转至sso登录界面 去完成用户认证,解决who are you 的问题,然后个子系统根据拿到的用户信息,匹配子系统中的用户权限,然后使用子系统.但是这样的问题在于,SSO server端 和子系统端都需要

asp.net5中用户认证与授权(2)_实用技巧

上篇文章给大家介绍了asp.net5中用户认证与授权(1),基础建立好了,紧接着就要创建对基础类进行操作的类,也就是实现基础类的增删改查当然,为了使用asp.net5的认证机制,这些都是通过特定的接口来实现的. 比如,对于角色来说,角色管理要实现的接口如下: public interface IQueryableRoleStore<TRole> : IRoleStore<TRole>, IDisposable where TRole : class { IQueryable<

asp.net5中的用户认证与授权(1)_实用技巧

就在最近一段时间,微软又有大动作了,在IDE方面除了给我们发布了Viausl Studio 2013 社区版还发布了全新的Visual Studio 2015 Preview. asp.net5中,关于用户的认证和授权提供了非常丰富的功能,如果结合ef7的话,可以自动生成相关的数据库表,调用也很方便. 但是,要理解这么一大堆关于认证授权的类,或者想按照自己项目的特定要求对认证授权进行定制,确实很头疼.为了解决这个问题,需要从根本上理解认证和授权的机制,不过这不是个简单的事情,一些概念也比较抽象,

Chinasec统一身份认证和授权管理解决方案

在单位中,各种IThttp://www.aliyun.com/zixun/aggregation/14223.html">应用系统越来越多,包括各种服务资源.计算机终端.计算机外设.应用程序和网络等各种企业资源的合理分配和使用越来越重要,而分散的身份认证和授权管理让管理员疲于应付,并且容易遗留安全漏洞 ,建立一个统一的身份认证和授权管理体系愈发重要. 面临的威胁: 各种应用系统都使用独立的用户名和密码,员工职位变更给管理员带来很大的工作量,并容易造成安全漏洞: 计算机的使用难以控制,经常发

ASP.NET中的认证与授权

用户认证 .net提供了3种用户认证的方式,分别是Windows,Forms,Passport.这几种形式的定义可以在网站根目录下Web.config中的authentication节点中看见.Windows是默认的验证形式,它是根据机器的访问权限来判断的.Passport是微软提供的一种验证形式,不常用.我们需要的知道并了解的是forms形式.forms验证就是表单认证,提供了以身份id和密码的形式进行验证和授权管理的功能. 在正式使用forms验证之前我们先看看它运行的一个流程: 从上图我们

ASP“.NET研究”.NET中的认证与授权

用户认证 .net提供了3种用户认证的方式,分别是Windows,Forms,Passport.这几种形式的定义可以在网站根目录下Web.config中的authentication节点中看见.Windows是默认的验证形式,它是根据机器的访问权限来判断的.Passport是微软提供的一种验证形式,不常用.我们需要的知道并了解的是forms形式.forms验证就是表单认证,提供了以身份id和密码的形式进行验证和授权管理的功能. 在正式使用forms验证之前我们先看看它运行的一个流程: 从上图我们

一起谈.NET技术,ASP.NET中的认证与授权

用户认证 .net提供了3种用户认证的方式,分别是Windows,Forms,Passport.这几种形式的定义可以在网站根目录下Web.config中的authentication节点中看见.Windows是默认的验证形式,它是根据机器的访问权限来判断的.Passport是微软提供的一种验证形式,不常用.我们需要的知道并了解的是forms形式.forms验证就是表单认证,提供了以身份id和密码的形式进行验证和授权管理的功能. 在正式使用forms验证之前我们先看看它运行的一个流程: 从上图我们

如何在Web系统中快速便捷地实现认证和授权系统

访问控制与 RBAC 模型 访问控制 通常的多用户系统都会涉及到http://www.aliyun.com/zixun/aggregation/38609.html">访问控制,所谓访问控制,是指通过某种方式允许活限制用户访问能力及范围的一种方法.这主要是由于系统需要对关键资源进行保护,防止由于非法入侵或者误操作对业务系统造成破坏.简而言之,访问控制即哪些用户可以访问哪些资源. 一般而言,访问控制系统包括三个组成部分: 主体:发出访问请求的实体,通常指用户或者用户进程. 客体:被保护的资源