随笔 - 6, 文章 - 1, 评论 - 135, 引用 - 0
数据加载中……

最新评论

共3页: 1 2 3 下一页 
我记得SoapHeader在MSDN里面就有很详细的说明

另外,楼主提到客户端有Flex和Asp.Net,这个Asp.Net就是一个Web站点吧?是的话,楼主要注意下了,如果是Flex的话,应该是用户直接通过Flex调用WebService,那么当前用户的计算机就是实际的WebService客户端,但如果用户是访问某个Web站点,然后由这个Web应用程序再去访问WebService,那么此时对于WebService来说,实际上客户端只是这台Web站点的服务器,而不是这个Web站点的实际用户计算机,在进行身份验证的时候就需要注意下,需要在你的Asp.Net程序里面向WebService提供当前实际用户的身份凭证,个人觉得从这点看,Session就不是很合适了,SoapHeader反而可以比较方便的解决这个问题。
http://www.cnblogs.com/rosanshao/archive/2007/10/14/923906.html
这儿能解决你的问题 ,这儿有比较详细的解决方案,使用Server端使用Session,Client使用CookieConter,如果是Flex也是一样的,获取到Cookie后,提交到服务器。这样的解决,改动,扩展比较方便。

使用SoapHeader也可以,如果你的方法比较多,每个WebService都要去加一句判断,相当不方便。可以加个HttpMoudle,判断SoapHeader的用户名和密码,以及请求的URL来判断是古接受此请求。
谢谢,谢谢大家我的给我的意见,非常感谢!现在关于如何实现身份验证,初具皱形了,荐与网上一些代码写了很或类似的但是并不是完全准确,而且对于WebService的一些SoapHeader在用法,什么时候需要实例化,什么时候要指定Direction = SoapHeaderDirection.Out(或In)非常重要没有具体的事例,故帖出我现在写了的一些代码,经参考,已传到网上在Asp.Net和Flex客户端调用测试成功!

在WebService服务器端:
public HeaderContainer header;//申明一个SoapHeader
//登陆,成功之后暂返回用户实体里面的用户ID,然后在发送到客户端以标识用户,MemberItem为用户Model
[WebMethod(Description = "根据用户名密码返回用户详细信息,返回NULL则登陆失败!",EnableSession=true)]
[System.Xml.Serialization.XmlInclude(typeof(MemberItem))]
[SoapHeader("header", Direction = SoapHeaderDirection.Out)]
public MemberItem MemberLogin(string username, string password)
{
if (username.Equals(string.Empty) || password.Equals(string.Empty))
return null;
MemberItem item = MemberManager.MemberLogin(username, password);

header = new HeaderContainer();
if (item != null)
header.SessionID = item.Member_inner_code;
return item;
}
//修改密码,需要有才登陆后的唯一标识
[WebMethod(Description = "修改指定用户的密码,且要修改的用户为当前登陆的标识的用户.",EnableSession=true)]
[SoapHeader("header", Direction = SoapHeaderDirection.In)]
public bool MemberChangePwd(int memberID, string password)
{
if (password.Equals(string.Empty))
return false;

if (header != null)
{
if (header.SessionID == memberID)
{
MemberManager.MemberChangePwd(memberID, password);
return true;
}
else return false;
}
return false;
}

//在.Net的客户端的调用
MallMember m = new MallMember();//申明页面级全局WebService
//登陆
MemberItem item = m.MemberLogin("123", "123");
if (item != null)
{
Session["Member"] = m.HeaderContainerValue;//登陆成功在保存从服务器端发送过来的标识
}
else Response.Write("失败!");
//修改密码
MallMember.HeaderContainer header = (MallMember.HeaderContainer)Session["Member"];
m.HeaderContainerValue =header;//给SoapHead(里面包含有SessionID)赋值一起发送到服务器端去,服务器能接受并处理。
Response.Write(m.MemberChangePwd(123,"123"));

//Flex客户端调用
private var m:MallMember=new MallMember();//申明全局WebService
var h:HeaderContainer;//申明一个SoapHeader头
public function login():void{ m.addmemberLoginEventListener(loginHandler);
m.memberLogin('allen','aaaaaa');
}
//登陆判断,注意headers[0].content as HeaderContainer,因为他返回的数组,因为可能有多个SoapHeader,而我们就只用到一个而已
public function loginHandler(event:MemberLoginResultEvent):void{
if(event.result!=null){
h=event.headers[0].content as HeaderContainer;
Alert.show("登陆成功");
}
}
//为什么要传的是HeaderContainer0,而在去指定HeaderContainer,可能是因为它代理类的原因,添加WebService引用后自动生成的,
public function update():void{
if(h!=null){
var h0:HeaderContainer0=new HeaderContainer0();
h0.HeaderContainer=h;
m.addmemberChangePwdEventListener(updateHandler);
m.addmemberChangePwd_header(h0);
m.memberChangePwd(1,"mima");
}
}
更新事件
public function updateHandler(event:MemberChangePwdResultEvent):void{
if(event.result!=null){
Alert.show("更新成功"); }
}
//异常处理
public function fault(event:FaultEvent):void{ Alert.show("出现异常!"+event.fault.faultString);
}

现在大问题处理了,就是那个权限即SessionID的问题了,上述咱保存的是用户的编号(只为传递SoapHeader做测试),可知这样是绝对不安全的,如何别人知道你的用户ID了岂不就能直接操作?所以要产生一个想Session一样的唯一会话ID给用户来标识,起到和Session一样的效果,而每次在SoapHeader里面传递的就只是SessionID了,在者每次传递用户名和密码,当回发到服务器端时再去查询数据库去验证,但安全也是个问题,传递过程中用MD5加密?本来就很麻烦了再添麻烦?还有一中解决方案是在数据库里面建一个OnLine在线表,每个在线用户分配一个GUID唯一标识,再定隔一定时间更新即相当于会话超时时间,能起到Session同等的效果,但是感觉性能欠佳,故请大家给点意见,非常感谢!!!
我觉得博主是否可以考虑实现System.Web.SessionState.IRequiresSessionState 接口?

MSDN对这个接口的描述是:Specifies that the target HTTP handler requires read and write access to session-state values. This is a marker interface and has no methods.

我建议是:
1. 让服务端的WebService实现IRequiresSessionState接口,这个接口没有任何方法,相当于只是一个标记。
2. 客户端把认证的Cookie和SessionId都发回到服务端。

这样应该就行了。
Forget web service.

If you are using .Net as your application tier. FluorineFX is a good choice.

At least you can call your assembly directly.

Open source and there are lot's of samples in your installed folder.

BTW.
If you use Flex as your font tool. Why do you need 如果我要调用ChangePwd方法前我一定要判断用户是否Login了? After user login, you can just create a varible to remeber the user has login or not. Right?
Usually I use UserId to be the flag.

cookie 当然是可以用的否则


使用方法和表单验证是一样的;

这种方式用 SoapHeader 有些多余;

asp.net ajax 也可以用webservice 就是 表单验证方式
也就是用的 cookie

[WebMethod(EnableSession=true)] 不加好像 cookie 也是好用的;

Flex 不是 flash 吗?这个我不太了解了
flash 应该自动使用浏览器 cookie 的吧?就算不使用也能通过和js通讯实现读写 cookie

有了 cookie 自然就有了 session 了!

接着使用标准的 asp.net 认证方式就可以了;和 page 一样,没认证的就会跳转到登录页,webserver 就是会出错了。



比较标准的做法就是使用SoapHeader。
一般把用户的登入凭证使用MD5加密后,直接存储在SoapHeader中,如果你在服务器端使用Cache缓存管理,也可以分配临时会话ID(相当于SessionID),管理你对此客户的服务资源——主要是状态信息。

使用Enterlib的Security,Cache库,很容易实现这个方案。
前段时间搞了一个C++调用WebService的东东,也是需要登录,遇到了和楼主类似的问题。C++类库中还没有CookieContainer,只好自己扩展了一个来保存。
其实问题主要在客户端,客户端如果不能保存cookies的话,服务器端怎么改都没用。
你可以抓取报文看看。在http头里面jsessionid每次是否一致
不知道能不能帮上你,我这个是用
c#的客户端调用java端的webservice,所以session是用jsessionId
class TransmitAdapter
{
private static string _jSessionID = string.Empty;
private static TransmitAdapter _instance;

/// <summary>
///
/// </summary>
private TransmitAdapter()
{
}

public static HttpWebResponse retrieveSessionID(HttpWebResponse webResponse)
{
char[] sep = { ';' };
String[] headers = webResponse.Headers["Set-Cookie"].Split(sep);
for (int i = 0; i <= headers.Length - 1; i++)
{
if (headers[i].StartsWith("JSESSIONID"))
{
sep[0] = '=';
_jSessionID = headers[i].Split(sep)[1];
break;
}
}
return webResponse;
}



public static TransmitAdapter Instance
{
get
{
if (_instance == null)
{
_instance = new TransmitAdapter();
}
return _instance;
}
}

public string SessionID
{
get { return _jSessionID; }
set { _jSessionID = value; }
}

}
--引用--------------------------------------------------
jillzhang: web service不像web,他是stateless的。使用SoapHeader是正常的解决方案
--------------------------------------------------------
同意!
之前也碰到类似问题,在webservice写session不成功,后来换了种方法,把信息写入硬盘。关注中
web service不像web,他是stateless的。使用SoapHeader是正常的解决方案
@swsd
谢谢,但是我试了你的那种方法,不行啊,抱错了啊,根本就得不到String name=header.Name;
String password=header.Password; 为空了。
既然能用FLEX 为什么不考虑SL?
从FLEX到.NET,这样跨越太大.受WEBSERVICES的限制,以后可能还会遇到意想不到的问题..


楼主你说用SessionState=SqlServer模式.我想这和Inproc是一样的吧,只不过是把会话数据从进程中转到了数据库中而已.你的会话还是会丢失.因为WEBSERVICES是无状态的.
按道理来说,你WEBSERVICES起用会话后,应该是可以了呀.莫非必须要在ASP.NET中,我想应该也是这样了.

所以你要手动处理Session,而且你在客户端要记录这个会话ID.
而且每次请求都要POST这个ID回来.
你可以写个基类,在WEBSERVICES基类中处理
不知道可不可以截取WEBSERVICES,扩展ISAPI?
@swsd
我大概看懂了你什么意思,你就是把用户名和密码保存在SoapHeader,然后每次再回调的时候在根据传回的用户名和密码去判断权限,那我在Flex的客户端还不要每次把用户名和密码传回到服务器端了,而在服务器端我每次也要去验证,而且还不知道怎么去验证?是保存那里,还是每次都去查询数据库?感觉不怎么妥,不知道还有没有更僚瞥一点的方法呢?
谢谢你提出了使用SoapHeader的具体方案,考虑一下。
例如,确定修改密码,在WebService里加上如上定义

public CheckUserSoapHeader header;

[WebMethod]
[SoapHeader("header")]
public void ChangePassword(String newpassword)
{
if (CheckUserStatus())
{
return false;
}
else
{
//这里修改密码
return trur;
}
}

CheckUserStatus定义如下:
private bool CheckUserStatus()
{
if (header == null)
{
return false;
}
else
{
String name=header.Name;
String password=header.Password;

//以下是确认用户代码

}
}

CheckUserSoapHeader定义如下:

public class CheckUserSoapHeader:SoapHeader
{
public String Name{get;set;}
public String Password{get;set;}

public CheckUserSoapHeader(String name,String password)
{
this.Name= name;
this.Password= password;
}
}

在Flex调用WebService时,先调用以下函数添加SoapHeader信息:

private function addHeader():void{
var q1:QName=new QName("http://temp/", "CheckUserSoapHeader");
var header:SOAPHeader=new SOAPHeader(q1, {Name:"test",Password:"111111"});

handler.clearHeaders();
handler.addHeader(header);
}


我这个项目用的就是soapheader添加一个属性
[SoapHeader("myHeaderMemberVariable", Direction = SoapHeaderDirection.Out)]
public bool AppLogin( string username, string password )
@swsd
你的意思是不是SoapHeader头里面添加一个属性,用来保存用户的唯一标识,然后在再每次回发的时候再去判断SoapHeader头里面有没有这个属性?能不能给出一些具体的Code,比如我再成功Login后怎么样,Changepwd里面怎么判断?
到目前为止,WebServices还可以说是一种无状态(stateless)的服务。

  所谓stateless就意味着不保存客户端服务调用者的任何信息。这是由WebServices的本质所决定的。WebServices在本质上是要为应用程序之间提供数据通讯的标准,为企业应用之间动态地提供大颗粒度的服务,所以WebServices并不适合于非常精细的基于会话的方法调用以及复杂的事务(transaction)处理之中。

  也许有人会对我这点提出异议!因为,现在有很多WebServices的产品(如WASD),不但可以保存session的信息,使服务成为有状态(stateful)的服务,而且还实现了remoteinterface,可以在WebServices的会话中传递远程对象的句柄,让客户端可以操纵递远程对象(详细信息请参考:XML数据中,可以互相传送任何数据,包括sessionID和transactionID,有了这些ID,从技术角度上说,实现有状态(stateful)的服务和事务处理并不复杂。但是,这样功能缺少标准的支持,当前版本的WSDL还无法表示这些复杂的服务。在企业内部,你可以任意使用这些特殊的功能,可以自己定义会话状态的交互协议,因为服务者和服务调用者之间的通讯都在你的控制之中;然而要将这些服务发布到Internet上,其他的应用程序是无法根据标准去识别这些特殊功能。
没看懂LZ的意思,不过对于用户验证,我的做法是:
Login后,调用WebMethod时,都把用户信息集成在SoapHeader里,在WebMethod上加上属性:

[SoapHeader("header")]
public void MethodName()
{
//一些身份验证函数
}

下面我贴一段已有朋友帮我想出的解决方案及其问题

--引用--------------------------------------------------
killkill: 写这方面的经验比较少,但是能不能要求Flex每次发送请求的时候在参数里面附加一个SessionID呢,而SessionID由你的程序产生,例如GUID,基本原理就是你自己重新实现一个Session。
--------------------------------------------------------


--引用--------------------------------------------------
Jonllen Peng: @killkill
这个我曾经考虑过,你的意思是不是当我成功Login后传回到客户端一个参数,这个参数就是自己产生的一个SessionID,然后当我再调用ChangePwd方法的时候把这个SessionID传回来,就能够标识了,你是不是这个意思?但是我WebService里面有好多方法,用到增、删、改和后台基本上都要用到权限判断,那我乞不是在调用的每个方法里面都要加一个保存SessionID的参数?
请问你知道Flex会不会接收到Asp.Net中产生的Session对象,如果能的话当前还可以解决问题,好象可以用,不过Flex好象产生的swf文件和as脚本都在客户端生成,无所谓服务器,那Session怎么用?但是最好还是能在WebService中做权限验证为好,不然那别人调用我的WebService就直接操作那还有什么安全可言。
--------------------------------------------------------


--引用--------------------------------------------------
killkill: 所谓Session的实现,据我见过的WebAPP都是由客户端回传一个SessionID的,这个SessionID存在于Cookie中,并不会附带任何数据,当然不会有非常“强大”的Session对象了。
Session的数据是存在于服务器端,客户端仅仅保存一个SessionID。
如果通过抓包分析的话,即使原始的Cookie纪录的SessionID也是可以得到,并可被第三方窃取的,所以我个人认为,手动实现Session和自动Session的安全性应该是同级的。
手动实现的副作用就是你每个WS方法都要多个参数了。
我的方案是这样的,在服务器端维护一个这样的数据结构
假设SessionID为GUID
Dictionary&lt;Guid,Dictionary&lt;string,object&gt;&gt; Sessions
登陆后 Sessions.Add&lt;SessionID,new Dictionary&lt;string,object&gt;())
判断是否登陆就 Sessions.ContainsKey(SessionID);
用某个Session[&quot;key&quot;]就这样 Sessions[SessionID][&quot;key&quot;]
当然Session的超时,LZ还是要想办法的 :)
虽然显得很笨拙,但是按照LZ描述的情况来看,笨拙点应该是可以接受的 :&gt;
--------------------------------------------------------


--引用--------------------------------------------------
Jonllen Peng: @killkill
谢谢!非常感谢再次回帖,但是我觉得还是那个问题,如果要我在每个WebService方法里面多加一个保存SessionID的参数的话,感觉太麻烦了,如果我每个都加一个参数的话,那可能又会出现一些问题了,比如我Login成功后我是返回一个用户的Model的,登陆失败的话则返回NULL,成功就返回的Model里面包含了用户的一些字段信息,那我返回的SessionID那又如何传回?我个每一个WebService都有返回值的,难道我在参数里面多加一个ref或out类型的参数,那在WebService中又是怎么样的,目前还没有测试行不行,又如果用了参数返回了SessionID,那我客户端不也要申明一个全局变量来保存SessionID?麻烦!,而且我不知道new Dictionary&lt;string,object&gt;())你那样能不能实现持久?我的基本功不怎么杂实,如果我再次回调时候Dictionary里面还会有没有object,还没有测试过。
不过我好象想到了一个办法,就是说还是用Session保存对象,只不过在Web.Config文件内配置SessionState为一个保存在数据里面的模式,好象有这个中模式,不知道行不行?但是可能还是存在有同样的问题?
--------------------------------------------------------


看来你得把权限管理系统做成一个WebService,登录成功后,你要把某一验证成功的标识信息传到客户端(aspx,Flex),在客户端保存这一标识后,每次调用后台webservice function时,作为参数传进去,我不知道.net是否可以做aop,如果可以,就可以拦截每一个function,进行权限判断了。
@第一控制.NET
我在每个要用Session的WebMethod方法里面都已加了EnableSession=true,不然都会用不了Session而且会报错,现在不是这个问题了,仍然谢谢!
webservice上加上属性
[WebMethod(EnableSession=true)]
public void MethodName()
{}
里面就可以直接用session了。
@Jonllen Peng
实现Dictionary....., 很容易,放在一个Singleton实例就是了 。
SessionID只是在Login后给客户端,由客户端保存
每次发送请求,附带就可以
@killkill
谢谢!非常感谢再次回帖,但是我觉得还是那个问题,如果要我在每个WebService方法里面多加一个保存SessionID的参数的话,感觉太麻烦了,如果我每个都加一个参数的话,那可能又会出现一些问题了,比如我Login成功后我是返回一个用户的Model的,登陆失败的话则返回NULL,成功就返回的Model里面包含了用户的一些字段信息,那我返回的SessionID那又如何传回?我个每一个WebService都有返回值的,难道我在参数里面多加一个ref或out类型的参数,那在WebService中又是怎么样的,目前还没有测试行不行,又如果用了参数返回了SessionID,那我客户端不也要申明一个全局变量来保存SessionID?麻烦!,而且我不知道new Dictionary<string,object>())你那样能不能实现持久?我的基本功不怎么杂实,如果我再次回调时候Dictionary里面还会有没有object,还没有测试过。
不过我好象想到了一个办法,就是说还是用Session保存对象,只不过在Web.Config文件内配置SessionState为一个保存在数据里面的模式,好象有这个中模式,不知道行不行?但是可能还是存在有同样的问题?
所谓Session的实现,据我见过的WebAPP都是由客户端回传一个SessionID的,这个SessionID存在于Cookie中,并不会附带任何数据,当然不会有非常“强大”的Session对象了。
Session的数据是存在于服务器端,客户端仅仅保存一个SessionID。
如果通过抓包分析的话,即使原始的Cookie纪录的SessionID也是可以得到,并可被第三方窃取的,所以我个人认为,手动实现Session和自动Session的安全性应该是同级的。
手动实现的副作用就是你每个WS方法都要多个参数了。
我的方案是这样的,在服务器端维护一个这样的数据结构
假设SessionID为GUID
Dictionary<Guid,Dictionary<string,object>> Sessions
登陆后 Sessions.Add<SessionID,new Dictionary<string,object>())
判断是否登陆就 Sessions.ContainsKey(SessionID);
用某个Session["key"]就这样 Sessions[SessionID]["key"]
当然Session的超时,LZ还是要想办法的 :)
虽然显得很笨拙,但是按照LZ描述的情况来看,笨拙点应该是可以接受的 :>
@killkill
这个我曾经考虑过,你的意思是不是当我成功Login后传回到客户端一个参数,这个参数就是自己产生的一个SessionID,然后当我再调用ChangePwd方法的时候把这个SessionID传回来,就能够标识了,你是不是这个意思?但是我WebService里面有好多方法,用到增、删、改和后台基本上都要用到权限判断,那我乞不是在调用的每个方法里面都要加一个保存SessionID的参数?
请问你知道Flex会不会接收到Asp.Net中产生的Session对象,如果能的话当前还可以解决问题,好象可以用,不过Flex好象产生的swf文件和as脚本都在客户端生成,无所谓服务器,那Session怎么用?但是最好还是能在WebService中做权限验证为好,不然那别人调用我的WebService就直接操作那还有什么安全可言。
写这方面的经验比较少,但是能不能要求Flex每次发送请求的时候在参数里面附加一个SessionID呢,而SessionID由你的程序产生,例如GUID,基本原理就是你自己重新实现一个Session。
@laper
恕我愚钝,'把session作为webservice调用的flag'什么意思,能不能具体一点。
@Scott Xu(南方小鬼)
EnableSession=true那个我早就写了啊,只要要用到Session的WebService里面我都写了的,不然你用Session的时候就会报错了。仍然谢谢!
我觉得把session作为webservice调用的flag应该也可以解决这个问题,进攻参参考。:)
[WebMethod(EnableSession=true)]
看不清楚你写的,乱七八糟
其实很多的技术我们并没有必要去记住它的具体实现,计算机以及网络本身就给我们提供了一个技术信息平台.很多时候我们只要能够找到它 ,并且能够看懂,再加上如何运用到自己的具体工作中去.如果做到了这几点,我相信已经是一个不错的程序员了.我的一个大哥和我说过一句很有道理的话:程序员就是解决问题的,在解决问题的时候不必在乎用什么方式.
--引用--------------------------------------------------
李战: <img src="http://www.cnblogs.com/Emoticons/yoyocici/223852199.gif" alt="" />

--------------------------------------------------------
严重影响视力的一篇博文。。。。。。。
看这篇文章觉得好累哦,为什么不分段呢?咳!
这是啥东西啊,乱七八糟的
共3页: 1 2 3 下一页