一、WebApi中为什么需要身份认证
我们在使用WebApi的时候,都是通过URL去获取数据。也就是说,任何人只要知道了URL地址,就能随意的访问后台的服务接口,就可以访问或者修改数据库数据了,这样就会导致很严重的后果。

1、我们不加身份认证,匿名用户可以直接通过url随意访问接口:

2、增加了身份认证之后,只有带了票据的请求才能访问对应的接口。

二、常见的认证方式
WebApi中常见的认证方式有如下几种:

FORM身份验证
集成WINDOWS验证
Basic基础认证
Digest摘要认证
三、Basic基础认证
Basic基础认证原理
Basic认证的基本原理就是加密用户信息生成Ticket,每次请求后端API接口的时候把生成的Ticket信息加到http请求的头部传给后端进行验证。具体步骤如下:

1、登录的时候验证用户名和密码,如果验证通过,则将用户名和密码按照一定的规则生成加密后的票据信息Ticket,然后将Ticket传递到前端。
2、如果登录成功,前端定义一个全局的变量接收API接口返回的Ticket信息。
3、前端界面再次发起ajax请求后端API接口的时候,将Ticket信息加入到HTTP请求的Head里面,将Ticket信息随着http请求一起发送到后端API接口。
4、在后端的WebApi服务中定义一个类,该类继承自AuthorizeAttribute类,然后重新父类里面的OnAuthorization方法,在OnAuthorization方法里面,通过actionContext参数取得http请求的Head,从Head里面可以获取前端传递过来的Ticket信息。将Ticket解密得到用户名和密码,然后验证用户名和密码是否正确。如果正确,表示验证通过。如果不正确,则返回401未授权的错误。
四、Basic基础认证示例代码
假设我们要访问Users控制器的Get接口,该接口方法返回int类型的List集合。

1、登录的API接口
`using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Security;
using WebApiBasicAuthorize.CustomerAttribute;
using WebApiBasicAuthorize.Entity;

namespace WebApiBasicAuthorize.Controllers
{
[BasicAuthorize]
public class UsersController : ApiController
{
/// <summary>
/// 允许匿名登录
/// </summary>
/// <param name="account"></param>
/// <param name="password"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet]
public IHttpActionResult Login(string account,string password)
{
ReturnValueEntity entity = new ReturnValueEntity();
// 真实生产环境中要去数据库校验account和password
if (account.ToUpper().Trim().Equals(“ADMIN”) && password.Trim().Equals(“123456”))
{
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, account, DateTime.Now,
DateTime.Now.AddHours(1), true, string.Format(“{0}&{1}”, account, password),
FormsAuthentication.FormsCookiePath);
var result = new { Result = true, Ticket = FormsAuthentication.Encrypt(ticket) };
entity.Result = true;
entity.Ticket = FormsAuthentication.Encrypt(ticket);
}
else
{
entity.Result = false;
entity.Ticket = “”;
}
return Json<ReturnValueEntity>(entity);
}

  1. [HttpGet]
  2. public IHttpActionResult Get()
  3. {
  4. List<int> list = new List<int>();
  5. list.Add(1);
  6. list.Add(2);
  7. list.Add(3);
  8. list.Add(4);
  9. list.Add(5);
  10. return Json<List<int>>(list);
  11. }
  12. }

}在Login方法上面添加 [AllowAnonymous]特性,表示允许匿名登录。2、基础认证接口using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Security;

namespace WebApiBasicAuthorize.CustomerAttribute
{
/// <summary>
/// 自定义特性继承自AuthorizeAttribute
/// </summary>
public class BasicAuthorizeAttribute:AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
// 从当前http请求Request对象的头部信息里面获取Authorization属性
var authorization = actionContext.Request.Headers.Authorization;
// 判断控制器获取action方法上面是否有AllowAnonymousAttribute特性,如果有,则允许匿名登录
if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0
|| actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0)
{
base.OnAuthorization(actionContext);
}
else if (authorization != null && authorization.Parameter != null)
{
// 验证用户逻辑
if (ValidateTicket(authorization.Parameter))
{
// 验证通过
base.IsAuthorized(actionContext);
}
else
{
this.HandleUnauthorizedRequest(actionContext);
}
}
else
{
// 返回401没有授权的状态码
this.HandleUnauthorizedRequest(actionContext);
}

  1. }
  2. /// <summary>
  3. /// 验证Ticket信息
  4. /// </summary>
  5. /// <param name="encryptTicket"></param>
  6. /// <returns></returns>
  7. private bool ValidateTicket(string encryptTicket)
  8. {
  9. // 解密Ticket
  10. var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
  11. // 从Ticket里面获取用户名和密码
  12. int index = strTicket.IndexOf("&");
  13. //string strUser=strTicket
  14. string[] array = strTicket.Split('&');
  15. string strUser = array[0];
  16. string strPwd = array[1];
  17. // 真实生产环境中应该用解密的用户名和密码去数据库验证,这里为了演示方便
  18. // 假定用户名是Admin,密码是123456
  19. if(strUser.Equals("Admin")&&strPwd.Equals("123456"))
  20. {
  21. return true;
  22. }
  23. else
  24. {
  25. return false;
  26. }
  27. }
  28. }

}3、前端代码<!DOCTYPE html>

<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>权限认证</title>
<script src="jquery-1.10.2.min.js"></script>
<script>
// 定义全局的ticket变量,用来保存登录成功以后的Ticket值
var ticket;
window.onload=function(){

};

function Login(){
$.ajax({
url:”http://localhost:20033/api/users?account="+$("#acc").val().trim()+"&password="+$("#pwd").val().trim(),
type:”Get”,
dataType:”json”,
“headers”: {
“Content-Type”: “application/json”,
“cache-control”: “no-cache”
},
success:function(data){
if(result.Result){
ticket=data.Ticket;
}else{
alert(“失败”);
}
},
error:function(data){
alert(data);
}
});
};

function Test(){
alert(ticket);
$.ajax({
url:’http://localhost:20033/api/users‘,
type:”Get”,
dataType:”json”,
beforeSend:function(XHR){
//发送ajax请求之前向http的head里面加入验证信息
XHR.setRequestHeader(‘Authorization’,’BasicAuth ‘+ticket);
},
success:function(data){
alert(data);
},
error:function(data){
alert(data);
}

});

};
</script>
</head>

<body>
<div>
<div>
<label>用户名:</label>
<input type="text" id="acc">
</div>
<div>
<label>密码:</label>
<input type="password" id="pwd">
</div>
<div>
<input type="button" id="btnLogin" onclick="Login()" value="登录">
</div>
<div>
<input type="button" id="GetAccount" onclick="Test()" value="测试">
</div>
</div>
</body>
</html>`
这里需要说明的是,我们在发送ajax请求之前,通过XHR.setRequestHeader(‘Authorization’, ‘BasicAuth ‘ + Ticket); 这句向http请求的Head里面添加Ticket信息。

通过上面的几步就可以达到Basic认证的效果了。

注意:后端的WebApi接口要配置允许跨域访问。

4、优化
每增加一个控制器,都需要在相应的控制器上面加[BasicAuthorize]特性,可以定义一个公共的控制器父类,该父类继承自ApiController,然后其他控制器继承该父类。

更多相关文章

  1. Fuel:Kotlin / Android最简单的HTTP网络库
  2. Android手机访问web服务器(post请求)
  3. Android(安卓)SurfaceFlinger process 流程分析
  4. Android中Socket通讯类
  5. android 使用AsyncTask代替thread进行网络请求
  6. android通过httpClient请求获取JSON数据并且解析
  7. 解决Cordova https请求异常
  8. Android(安卓)之网络编程
  9. Android(安卓)网络请求库Retrofit简单使用

随机推荐

  1. 还有这种操作?浅析为什么要看源码
  2. Android(安卓)ActionBar的源代码分析(一)
  3. 干货丨时序数据库DolphinDB异常检测引擎
  4. Android百度地图的简单实现
  5. 聊一聊开发常用小工具
  6. 聊聊Zookeeper中的ZAB协议,保证你能看懂
  7. 带有过期时间的LRU实现(java版)
  8. Android中获取网络图片的三种方法
  9. java关键字系列(4)this
  10. android 4.0 StatusBar 架构