权限认证:是需要的,http地址,是公开的,所以需要权限认证
session–webapi默认是不支持session–RESTful—可以自行扩展去支持
无状态:第2次请求和第1次请求不关联
1 登陆过程,拿到令牌–token–ticket–许可证
2 验证成功–账号+密码+其他信息+时间–加密一下得到ticket—返回给客户端
3 请求时,ajax里面带上这个ticket(header)
4 接口调用时,就去验证ticket,解密一下,看看信息,看看时间
5 每个方法都需要验证下ticket,基于filter来实现
用户登入的后端api,返回token
#region 用户登陆
[CustomAllowAnonymousAttribute]
[HttpGet]
public string Login(string account, string password)
{
if ("Admin".Equals(account) && "123456".Equals(password))//应该数据库校验
{
FormsAuthenticationTicket ticketObject = 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(ticketObject)
};
return JsonConvert.SerializeObject(result);
}
else
{
var result = new { Result = false };
return JsonConvert.SerializeObject(result);
}
}
#endregion
用户登入的前端,获取token
$("#btnLogin").on("click", function () {
$.ajax({
url: "/api/users/Login",
type: "GET",
data: { "Account": $("#txtAccount").val(), "Password": $("#txtPassword").val() },
success: function (data) {
var result = JSON.parse(data);
if (result.Result) {
ticket = result.Ticket;
alert(result.Ticket);
}
else {
alert("failed");
}
}, datatype: "json"
});
});
var ticket = "";//登陆后放在某个html里面,ajax都得带上
用户请求,带上前面获取token
前端版
$("#btnGet1").on("click", function () {
//$.ajax({ url: "/api/users", type: "get", data: { "userName": "Superman" }, success: function (data) { alert(data); }, datatype: "json" });//指向接口,参数匹配的,大小写不区分
$.ajax({
//url: "/api/users/GetUserByName?ticket=" + ticket
url: "/api/users/GetUserByName", type: "get", data: { "username": "Superman" },
beforeSend: function (XHR) {
//发送ajax请求之前向http的head里面加入验证信息
XHR.setRequestHeader('Authorization', 'BasicAuth ' + ticket);
},
success: function (data) {
alert(data);
}, datatype: "json"
});
});
后端版
#region 用户登陆 获取ticket后使用
private void AuthorizationDemo()
{
string ticket = "";
{
string loginUrl = "http://localhost:8088/api/users/Login?Account=Admin&Password=123456";
var handler = new HttpClientHandler();//{ AutomaticDecompression = DecompressionMethods.GZip };
using (var http = new HttpClient(handler))
{
var response = http.GetAsync(loginUrl).Result;//拿到异步结果
Console.WriteLine(response.StatusCode); //确保HTTP成功状态值
//await异步读取最后的JSON(注意此时gzip已经被自动解压缩了,因为上面的AutomaticDecompression = DecompressionMethods.GZip)
ticket = response.Content.ReadAsStringAsync().Result.Replace("\"{\\\"Result\\\":true,\\\"Ticket\\\":\\\"", "").Replace("\\\"}\"", "");
//ticket = JsonHelper.StringToObject<TicketModel>(response.Content.ReadAsStringAsync().Result).Ticket;
}
}
{
string url = "http://localhost:8088/api/users/GetUserByName?username=superman";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 30 * 1000;
request.Headers.Add(HttpRequestHeader.Authorization, "BasicAuth " + ticket);//头文件增加Authorization
//request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36";
//request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
string result = "";
using (var res = request.GetResponse() as HttpWebResponse)
{
if (res.StatusCode == HttpStatusCode.OK)
{
StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
result = reader.ReadToEnd();
}
}
}
{
string url = "http://localhost:8088/api/users/GetUserByName?username=superman";
var handler = new HttpClientHandler();
using (var http = new HttpClient(handler))
{
http.DefaultRequestHeaders.Add("Authorization", "BasicAuth " + ticket);//头文件增加Authorization
var response = http.GetAsync(url).Result;
Console.WriteLine(response.StatusCode);
string result = response.Content.ReadAsStringAsync().Result;
}
}
}
#endregion
权限校验特性和跳过校验的两个特性
public class CustomBasicAuthorizeAttribute : AuthorizeAttribute
{
/// <summary>
/// action前会先来这里完成权限校验
/// </summary>
/// <param name="actionContext"></param>
public override void OnAuthorization(HttpActionContext actionContext)
{
//actionContext.Request.Headers["Authorization"]
if (actionContext.ActionDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null)
{
return;//继续
}
else if (actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null)
{
return;//继续
}
else
{
var authorization = actionContext.Request.Headers.Authorization;
if (authorization == null)
{
this.HandlerUnAuthorization();
}
else if (this.ValidateTicket(authorization.Parameter))
{
return;//继续
}
else
{
this.HandlerUnAuthorization();
}
}
}
private void HandlerUnAuthorization()
{
throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
}
private bool ValidateTicket(string encryptTicket)
{
////解密Ticket
//if (string.IsNullOrWhiteSpace(encryptTicket))
// return false;
try
{
var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
//FormsAuthentication.Decrypt(encryptTicket).
return string.Equals(strTicket, string.Format("{0}&{1}", "Admin", "123456"));//应该分拆后去数据库验证
}
catch (Exception ex)
{
return false;
}
}
}
public class CustomAllowAnonymousAttribute : Attribute
{
}
对于权限的控制器和方法注册就不说了,全局注册说下
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 配置和服务
config.DependencyResolver = new UnityDependencyResolver(ContainerFactory.BuildContainer());
//config.Filters.Add(new CustomBasicAuthorizeAttribute());//全局注册
config.Filters.Add(new CustomExceptionFilterAttribute());
config.Services.Replace(typeof(IExceptionHandler), new CustomExceptionHandler());//替换全局异常处理类
//config.EnableCors(new EnableCorsAttribute("*", "*", "*"));//全部都允许,
// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "CustomApi",//默认的api路由
routeTemplate: "api/{controller}/{action}/{id}",//正则规则,以api开头,第二个是控制器 第三个是参数
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",//默认的api路由
routeTemplate: "api/{controller}/{id}",//正则规则,以api开头,第二个是控制器 第三个是参数
defaults: new { id = RouteParameter.Optional }
);
}
}