关于WEB ServiceWCFWebApi实现身份验证之WEB Service篇
在这个WEB API横行的时代,讲WEB Service技术却实显得有些过时了,过时的技术并不代表无用武之地,有些地方也还是可以继续用他的,我之所以会讲解WEB Service,源于我最近面试时被问到相关问题,我这里只是重新复习一下并总结一下,给新手们指指路,大牛们可以无视之,当然不足之处还请大家指教,谢谢!
WEB Service身份验证,网上已有许多的相关文章,总结起来有:基于自定义SoapHeader验证、Form验证、集成Windows身份验证、服务方法加入一个或几个验证参数;下面就不废话了,直接分享实现的代码吧,中间有涉及注意的地方,我会有说明文字的。
1.基于自定义SoapHeader验证
定义服务:(注意UserValidationSoapHeader必需有无参构造函数,否则无法序列化)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
//UserValidationSoapHeader:
public class UserValidationSoapHeader : SoapHeader
{
public string UserName { get ; set ; }
public string Password { get ; set ; }
public UserValidationSoapHeader()
{ }
public bool IsValid()
{
if ( string .IsNullOrEmpty(UserName) || string .IsNullOrEmpty(Password))
{
throw new Exception( "用户名及密码不能为空!" );
}
if (! string .Equals(UserName, "admin" ) || ! string .Equals(Password, "123456" ))
{
throw new Exception( "用户名或密码不正确!" );
}
return true ;
}
}
//SoapHeaderWebService:
[WebService(Namespace = "http://www.zuowenjun.cn" )]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem( false )]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
[System.Web.Script.Services.ScriptService]
public class SoapHeaderWebService : System.Web.Services.WebService
{
public UserValidationSoapHeader userValidation;
[WebMethod(Description= "问候" )]
[SoapHeader( "userValidation" )]
public string HelloTo( string name)
{
if (userValidation.IsValid() && ! string .IsNullOrEmpty(name))
{
return "Hello " + name;
}
return "Hello World!" ;
}
}
|
客户端先通过服务地址引用服务,服务引用有两种,分为服务引用和WEB服务引用(后面涉及到服务引用的不再重述)
服务引用:(这里是按照WCF的模式来生成WEB服务代理类)
WEB服务引用:
(如果通过项目右键,则可以直接点击“添加WEB引用”到此画面)
客户端使用如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
private void CallWebServiceFromWebReference()
{
try
{
var svc = new RefWebSoapHeaderWebService.SoapHeaderWebService();
svc.UserValidationSoapHeaderValue = new RefWebSoapHeaderWebService.UserValidationSoapHeader() { UserName = "admin" , Password = "123456" };
string result = svc.HelloTo(TextBox1.Text);
Label1.Text = result;
}
catch (Exception ex)
{
Label1.Text = ex.Message;
}
}
private void CallWebServiceFromServiceReference()
{
try
{
var svc = new RefSoapHeaderWebService.SoapHeaderWebServiceSoapClient();
var header = new RefSoapHeaderWebService.UserValidationSoapHeader();
header.UserName = "admin" ;
header.Password = "123456" ;
string result = svc.HelloTo(header, TextBox1.Text);
Label1.Text = result;
}
catch (Exception ex)
{
Label1.Text = ex.Message;
}
}
protected void Button1_Click( object sender, EventArgs e)
{
if (RadioButtonList1.SelectedValue == "1" )
{
CallWebServiceFromServiceReference();
}
else
{
CallWebServiceFromWebReference();
}
}
|
上述代码我针对两种WEB服务引用作了不同的使用实例,关键看方法调用,服务引用下生成的服务方法参数中会自动加入一个soapHeader的参数,而WEB服务引用则没有,我感觉采用WEB服务引用基于这种验证比较方便,因为只需将soapHeader实例赋值一次就可以多次调用不同的服务方法。
2.Form验证
定义服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
//专门用于登录的WEB服务:
[WebService(Namespace = "http://www.zuowenjun.cn" )]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem( false )]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
[System.Web.Script.Services.ScriptService]
public class FormAuthWebService : System.Web.Services.WebService
{
[WebMethod]
public bool Login( string username, string password)
{
return UserBusiness.Login(username, password);
}
}
//正常的WEB服务:
[WebService(Namespace = "http://www.zuowenjun.cn" )]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem( false )]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
[System.Web.Script.Services.ScriptService]
public class FormAuthHelloWebService : System.Web.Services.WebService
{
[WebMethod]
public string HelloTo( string name)
{
if (! string .IsNullOrEmpty(name))
{
return "Hello " + name;
}
return "Hello World" ;
}
[WebMethod]
public void Logout()
{
UserBusiness.Logout();
}
}
//业务辅助类:
public static class UserBusiness
{
public static bool Login( string userName, string password)
{
if ( string .IsNullOrEmpty(userName) || string .IsNullOrEmpty(password))
{
throw new Exception( "用户名及密码不能为空!" );
}
if (! string .Equals(userName, "admin" ) || ! string .Equals(password, "123456" ))
{
throw new Exception( "用户名或密码不正确!" );
}
SaveLoginStauts(userName);
return true ;
}
public static bool IsAuthenticated()
{
return HttpContext.Current.Request.IsAuthenticated;
}
public static void Logout()
{
System.Web.Security.FormsAuthentication.SignOut();
}
private static void SaveLoginStauts( string userName)
{
System.Web.Security.FormsAuthentication.SetAuthCookie(userName, false );
}
}
|
从上面的代码可以看出,这里采用了基于ASP.NET FORM验证来保存登录状态,其它代码与正常无异
因为采用了ASP.NET FORM验证,所以web.config需要加入以下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//在system.web节点加入以下配置,因为我将WEB服务全部放到了Services目录下,所以仅对该目录进行了限制
< authentication mode="Forms">
< forms name="auth.webservice" loginUrl="~/Services/FormAuthWebService.asmx/Login">
</ forms >
</ authentication >
< webServices >
< protocols >
< add name="HttpSoap"/>
< add name="HttpPost"/>
< add name="HttpGet"/>
< add name="Documentation"/>
</ protocols >
</ webServices >
</ system.web >
< location path="Services">
< system.web >
< authorization >
< deny users="?"/>
</ authorization >
</ system.web >
</ location >
|
注意以下2点:
1.上面loginUrl="~/Services/FormAuthWebService.asmx/Login",这里我直接将未登录直接转到Login,原因是如果不加Login,那么你将无法在WEB浏览器上进行登录调试及其它服务方法的调试。
2.由于采用了FORM验证,且禁止匿名访问,造成无法正常引用服务,原因是服务引用也是一次HTTP请求,默认是未登录的情况,你去引用受限的服务地址,它就会自动跳转到登录的服务地址,所以针对这个问题,我采用了两种办法,第一种是:先不要禁止匿名访问,当服务引用成功后,再加上该配置,第二种是:不直接引用服务,采用代码动态请求服务方法来进行相关的调用,客户端使用代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
//第一种:采用服务引用:
protected void Button2_Click( object sender, EventArgs e)
{
try
{
CookieContainer cookieContainer = new CookieContainer();
var svc = new RefFormAuthLoginWebService.FormAuthWebService();
svc.CookieContainer = cookieContainer; //共享cookie容器
if (svc.Login( "admin" , "123456" ))
{
var svc2 = new RefFormAuthWebService.FormAuthHelloWebService();
svc2.CookieContainer = cookieContainer; //共享cookie容器
Label2.Text = svc2.HelloTo(TextBox2.Text);
}
}
catch (Exception ex)
{
Label2.Text = ex.Message;
}
}
//第二种:采用动态请求调用:
protected void Button2_Click( object sender, EventArgs e)
{
try
{
CookieContainer cookieContainer = new CookieContainer();
var result = CallWebServiceFromHttpWebRequest( "FormAuthWebService.asmx/Login" , "username=admin&password=123456" , cookieContainer);
Label2.Text = result.SelectSingleNode( "//ns:boolean" , GetXmlNamespaceManager(result.NameTable)).InnerText;
var result2 = CallWebServiceFromHttpWebRequest( "FormAuthHelloWebService.asmx/HelloTo" , "name=" + HttpUtility.UrlEncode(TextBox2.Text, Encoding.UTF8), cookieContainer);
Label2.Text = result2.SelectSingleNode( "//ns:string" , GetXmlNamespaceManager(result2.NameTable)).InnerText;
catch (Exception ex)
{
Label2.Text = ex.Message;
}
|
辅助方法定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
private XmlDocument CallWebServiceFromHttpWebRequest( string serviceUrl, string serviceParams,CookieContainer cookieContainer)
{
HttpWebRequest request =(HttpWebRequest)WebRequest.Create( "http://localhost:8768/Services/" + serviceUrl);
request.Method = "POST" ;
request.ContentType = "application/x-www-form-urlencoded" ;
request.Credentials = CredentialCache.DefaultCredentials;
byte [] data = Encoding.UTF8.GetBytes(serviceParams); //参数
request.ContentLength = data.Length;
request.CookieContainer = cookieContainer; //共享cookie容器
Stream writer = request.GetRequestStream();
writer.Write(data, 0, data.Length);
writer.Close();
WebResponse response = request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
String retXml =sr.ReadToEnd();
sr.Close();
XmlDocument doc = new XmlDocument();
doc.LoadXml(retXml);
return doc;
}
private XmlNamespaceManager GetXmlNamespaceManager(XmlNameTable table)
{
XmlNamespaceManager nsMgr = new XmlNamespaceManager(table);
nsMgr.AddNamespace( "ns" , "http://www.zuowenjun.cn" );
return nsMgr;
}
|
这里说明一下,不论是采用服务引用还是动态调用服务,均需确保引用同一个COOKIE容器,而且在动态调用服务时,还需注意最终返回的结果为XML,需要进行相应的解析才能得到指定的值,相关的注意事项,可参见这篇文章《C#操作xml SelectNodes,SelectSingleNode总是返回NULL 与 xPath 介绍》,其实看了过后就知道是XML命名空间的问题,也可以去掉命名空间,这样解析就方便多了,如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//这里是得到的XML,调用去除命名空间的方法:
String retXml = RemoveNamespace(sr.ReadToEnd());
private string RemoveNamespace( string xml)
{
var reg = new System.Text.RegularExpressions.Regex( "xmlns=\".*\"" , System.Text.RegularExpressions.RegexOptions.IgnoreCase);
return reg.Replace(xml, "" );
}
protected void Button2_Click( object sender, EventArgs e)
{
...
var result = CallWebServiceFromHttpWebRequest( "FormAuthWebService.asmx/Login" , "username=admin&password=123456" , cookieContainer);
Label2.Text = result.SelectSingleNode( "//boolean" ).InnerText;
var result2 = CallWebServiceFromHttpWebRequest( "FormAuthHelloWebService.asmx/HelloTo" , "name=" + HttpUtility.UrlEncode(TextBox2.Text, Encoding.UTF8), cookieContainer);
Label2.Text = result2.SelectSingleNode( "//string" ).InnerText;
...
}
|
3.集成Windows身份验证,这个很简单,首先将IIS设置成集成WINDOWS身份验证,服务定义无特殊代码
客户端使用如下:
1
2
3
|
Test.WebReference.Service1 service= new Test.WebReference.Service1(); //生成web service实例
service.Credentials = new NetworkCredential( "user" , "123456" ); //user是用户名,该用户需要有一定的权限
lblTest.Text =service.HelloTo( "zuowenjun" ) ; //调用web service方法
|
WEB页面示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
< form id="form1" runat="server">
< fieldset >
< legend >基于自定义SoapHeader验证后调用服务</ legend >
< div >
< asp:RadioButtonList ID="RadioButtonList1" runat="server" RepeatDirection="Horizontal">
< asp:ListItem Value="1">From Service Reference</ asp:ListItem >
< asp:ListItem Value="2">From Web Reference</ asp:ListItem >
</ asp:RadioButtonList >
< asp:TextBox ID="TextBox1" runat="server"></ asp:TextBox >
< asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
< br />
< asp:Label ID="Label1" runat="server" Text="Label"></ asp:Label >
</ div >
</ fieldset >
< p >
</ p >
< p >
</ p >
< p >
</ p >
< fieldset >
< legend >基于自定义Form身份验证后调用服务</ legend >
< div >
< asp:TextBox ID="TextBox2" runat="server"></ asp:TextBox >
< asp:Button ID="Button2" runat="server" onclick="Button2_Click" Text="Button" />
< br />
< asp:Label ID="Label2" runat="server" Text="Label"></ asp:Label >
</ div >
</ fieldset >
< p >
</ p >
< p >
</ p >
< p >
</ p >
< fieldset >
< legend >基于自定义Windows验证后调用服务</ legend >
< div >
< asp:TextBox ID="TextBox3" runat="server"></ asp:TextBox >
< asp:Button ID="Button3" runat="server" Text="Button"
onclick="Button3_Click" />
< br />
< asp:Label ID="Label3" runat="server" Text="Label"></ asp:Label >
</ div >
</ fieldset >
</ form >
|
最终呈现效果截图如下:
由于下班时间写的,所以有些仓促,不足之处,敬请指出,谢谢!~v~
补充知识点:
我上面的代码在验证用户登录时,若验证不通过,我是直接抛出一个Exception,WEB服务在返回到客户端前会被包装为SoapException类型的异常,这样导至在客户端无法很直接的查看错误内容,所以这里可以采用这篇文章《封装SoapException处理Webservice异常》里面的方法来添加格式化SoapException的方法及解析SoapException的方法。
关于WEB SERIVCE在多个ASP.NET页面中使用时共享COOKIE的办法,实现代码如下:
首先正常引用WEB服务,然后自定义继承自该引用的服务类,并在其构造函数中实例化CookieContainer并保存到静态字段中;
使用的时,不要调用引用的服务,而应该调用这些自定义的子类,从而实现共享COOKIE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public class FormAuthHelloWebServiceEx : RefFormAuthWebService.FormAuthHelloWebService
{
private static CookieContainer cookieContainer;
static FormAuthHelloWebServiceEx()
{
cookieContainer = new System.Net.CookieContainer();
}
public FormAuthHelloWebServiceEx(CookieContainer ckContainer)
{
if (cookieContainer != null )
{
cookieContainer = ckContainer;
}
this .CookieContainer = cookieContainer;
}
}
public class FormAuthWebServiceEx : RefFormAuthLoginWebService.FormAuthWebService
{
private static CookieContainer cookieContainer;
static FormAuthWebServiceEx()
{
cookieContainer = new System.Net.CookieContainer();
}
public FormAuthWebServiceEx(CookieContainer ckContainer)
{
if (cookieContainer != null )
{
cookieContainer = ckContainer;
}
this .CookieContainer = cookieContainer;
}
}
|
转载于:https://www.cnblogs.com/wzg168/p/8559195.html
关于WEB ServiceWCFWebApi实现身份验证之WEB Service篇相关推荐
- 关于WEB ServiceWCFWebApi实现身份验证之WebApi篇
之前先后总结并发表了关于WEB Service.WCF身份验证相关文章,如下: 关于WEB Service&WCF&WebApi实现身份验证之WEB Service篇. 关于WEB S ...
- 如何实现RESTful Web API的身份验证
最近想拿一个小项目来试水RESTful Web API,项目只有几个调用,比较简单,但同样需要身份验证,如果是传统的网站的话,那不用说,肯定是用户名+密码在登录页获得登录Token,并把登录Token ...
- php oauth2 和 jwt,jwt-auth: thinkphp 的 jwt (JSON Web Token)身份验证扩展包,支持Swoole...
JWT-AUTH thinkphp的jwt(JSON Web Token)身份验证包.支持Header.Cookie.Param等多种传参方式.包含:验证.验证并且自动刷新等多种中间件. 支持Swoo ...
- Asp.Net MVC及Web API添加身份验证及错误处理的过滤器
先说身份验证的问题.无论是mvc还是api都有一个安全性的问题,未通过身份验证的人能不能访问的问题.我们新一个空项目时,默认是没有身份验证的,除非你在控制器类或者方法上面加上Authorize属性才会 ...
- ntlm java_Java Web服务NTLM身份验证
我需要在Java Client Class中调用asp.net Web Service,我正在使用NTLM身份验证 . 但我得到例外"401 - 未经授权:由于凭证无效,访问被拒绝 . &q ...
- ASP.NET Core 3.1 系列之 Web API 添加身份验证Jwt
ASP.NET Core 3.1 系列之 Web API 中间件篇 (一) 身份验证(Jwt)中间件使用步骤 添加 NuGet程序包 添加包:Microsoft.AspNetCore.Authenti ...
- 用户登入身份验证,手机app登入身份验证,TokenAuth身份验证,JSON Web Token(JWT)身份验证
JJWT身份验证 1.pom依赖: <dependency ...
- Java web接入google身份验证器二次验证
实现原理参考: https://blog.seetee.me/post/2011/google-two-step-verification/ 第一步: maven工程加入依赖 <dependen ...
- web安全漏洞——身份验证绕过
目录 前言: 0x01 刷新令牌接口的配置错误 0x02 SSO配置不正确 0x03 基于CMS的权限问题
- 登录工程:传统 Web 应用中的身份验证技术
标题中 "传统 Web 应用" 这一说法也并没有什么官方定义,只是为了与"现代化 Web 应用"形成比较而自拟的一个概念.所谓现代化 Web 应用指的是那些基于 ...
最新文章
- [技术文档] 一劳永逸,用USB设备制作多系统引导
- 关于 DOM 操作的几个类型
- HDU 1257 最少拦截系统
- C#一列数的规则如下: 1、1、2、3、5、8、13、21、34...... 求第100位数是多少, 用递归算法实现。...
- modbus报文解析实例_云原生、全栈可编程的下一代SDN解析与实践 (一)丨传统SDN架构演进...
- BBC:乐在其中统计学 (2010)
- 计算机专业评副高论文要求,护士晋升副高职称论文要求
- java面试简历项目经验,java面试题项目中的难点
- 关于 red bend
- 打开组策略 计算机配置,组策略怎么打开? 打开组策略命令与4种方法-电脑教程...
- 2018.12.3比赛题目:电子警察
- 论文笔记1 MOEFL Multi-objective Evolutionary Federated Learning
- 【Python3】作业车间调度,SPT规则,LPT规则
- R语言数据可视化-条形图
- 现身说法,如何给上司送礼物
- mysql 测试数据库employees导入
- docker logs
- 一元函数积分学2_不定积分的分部积分法
- Elasticsearch的搜索命令
- SCT2601TVBR、LMR16006XDDCR、MP2456GJ-Z参数
热门文章
- Linux下cacti+syslog-ng+snare
- 十步叫你如何无损修复硬盘锁(mbr病毒)
- Codecraft-17 and Codeforces Round #391 (Div. 1 + Div. 2, combined)
- [javase] 1.请从键盘随机输入10个整数保存到List中,并按倒序、从大到小的顺序显示出来...
- 白皮 Chapter 1
- App调试内存泄露之Context篇(下)-App调试内存泄露之Context篇(下)
- Web前端开发所用的调试工具
- 软件测试经典问题——NextDate函数
- 云主机前景几何,风萧萧兮!
- StringUtils 方法介绍(转载)