WebApi Basic基础身份认证
一:为什么需要身份认证
没有身份认证,匿名用户只要知道了我们服务的url,就能随意访问接口

增加了身份认证后,只有拿到票据的请求才能访问接口

下面是代码示例
WEB前端
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body style="">
<canvas class="pg-canvas" width="1536" height="310"></canvas>
<div class="login">
<div class="login_title">
<span>管理员登录</span>
</div>
<div class="login_fields">
<div class="login_fields__user">
<div class="icon">
<img alt="" src="/Admin/img/user_icon_copy.png">
</div>
<input name="login" placeholder="用户名" maxlength="16" type="text" autocomplete="off" value="admin">
<div class="validation">
<img alt="" src="/Admin/img/tick.png">
</div>
</div>
<div class="login_fields__password">
<div class="icon">
<img alt="" src="/Admin/img/lock_icon_copy.png">
</div>
<input name="pwd" placeholder="密码" maxlength="16" type="text" autocomplete="off">
<div class="validation">
<img alt="" src="/Admin/img/tick.png">
</div>
</div>
<div class="login_fields__password">
<div class="icon">
<img alt="" src="/Admin/img/key.png">
</div>
<input name="code" placeholder="验证码" maxlength="4" type="text" autocomplete="off">
<div class="validation" style="opacity: 1; right: -5px; top: -3px;">
<canvas class="J_codeimg" id="myCanvas" onclick="Code();">对不起,您的浏览器不支持canvas,请下载最新版浏览器!</canvas>
</div>
</div>
<div class="login_fields__submit">
<input type="button" value="登录">
</div>
</div>
<div class="success">
</div>
<div class="disclaimer">
<p>欢迎登陆后台管理系统 </p>
<%--<p style="text-align:right;"><a href="Register.aspx" style="color:white;">注册</a></p>--%>
</div>
</div>
<div class="authent">
<div class="loader" style="height: 44px; width: 44px; margin-left: 28px;">
<div class="loader-inner ball-clip-rotate-multiple">
<div></div>
<div></div>
<div></div>
</div>
</div>
<p>认证中...</p>
</div>
<div class="OverWindows"></div>
<script type="text/javascript">
var canGetCookie = 0; //是否支持存储Cookie 0 不支持 1 支持
var ajaxmockjax = 1; //是否启用虚拟Ajax的请求响 0 不启用 1 启用
//默认账号密码
var truelogin = "admin";
var truepwd = "123456";
var CodeVal = 0;
Code();
function Code() {
if (canGetCookie == 1) {
createCode("AdminCode");
var AdminCode = getCookieValue("AdminCode");
showCheck(AdminCode);
} else {
showCheck(createCode(""));
}
}
function showCheck(a) {
CodeVal = a;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, 1000, 1000);
ctx.font = "80px 'Hiragino Sans GB'";
ctx.fillStyle = "#E8DFE8";
ctx.fillText(a, 0, 100);
}
$(document).keypress(function (e) {
// 回车键事件
if (e.which == 13) {
$('input[type="button"]').click();
}
});
//粒子背景特效
$('body').particleground({
dotColor: '#E8DFE8',
lineColor: '#133b88'
});
$('input[name="pwd"]').focus(function () {
$(this).attr('type', 'password');
});
$('input[type="text"]').focus(function () {
$(this).prev().animate({ 'opacity': '1' }, 200);
});
$('input[type="text"],input[type="password"]').blur(function () {
$(this).prev().animate({ 'opacity': '.5' }, 200);
});
$('input[name="login"],input[name="pwd"]').keyup(function () {
var Len = $(this).val().length;
if (!$(this).val() == '' && Len >= 5) {
$(this).next().animate({
'opacity': '1',
'right': '30'
}, 200);
} else {
$(this).next().animate({
'opacity': '0',
'right': '20'
}, 200);
}
});
var open = 0;
layui.use('layer', function () {
//var msgalert = '默认账号:' + truelogin + '<br/> 默认密码:' + truepwd;
//var index = layer.alert(msgalert, { icon: 6, time: 4000, offset: 't', closeBtn: 0, title: '友情提示', btn: [], anim: 2, shade: 0 });
//layer.style(index, {
// color: '#777'
//});
//非空验证
$('input[type="button"]').click(function () {
var login = $('input[name="login"]').val();
var pwd = $('input[name="pwd"]').val();
var code = $('input[name="code"]').val();
if (login == '') {
ErroAlert('请输入您的账号');
} else if (pwd == '') {
ErroAlert('请输入密码');
} else if (code == '' || code.length != 4) {
ErroAlert('输入验证码');
} else {
//认证中..
fullscreen();
$('.login').addClass('test'); //倾斜特效
setTimeout(function () {
$('.login').addClass('testtwo'); //平移特效
}, 300);
setTimeout(function () {
$('.authent').show().animate({ right: -320 }, {
easing: 'easeOutQuint',
duration: 600,
queue: false
});
$('.authent').animate({ opacity: 1 }, {
duration: 200,
queue: false
}).addClass('visible');
}, 500);
//登陆
var JsonData = { login: login, pwd: pwd, code: code };
//此处做为ajax内部判断
var url = "";
if (JsonData.code.toUpperCase() == CodeVal.toUpperCase()) {
url = "/Tools/Login.ashx";
} else {
url = "Ajax/LoginFalse";
}
AjaxPost(url, JsonData,
function () {
//ajax加载中
},
function (data) {
console.log(data);
//ajax返回
//认证完成
setTimeout(function () {
$('.authent').show().animate({ right: 90 }, {
easing: 'easeOutQuint',
duration: 600,
queue: false
});
$('.authent').animate({ opacity: 0 }, {
duration: 200,
queue: false
}).addClass('visible');
$('.login').removeClass('testtwo'); //平移特效
}, 2000);
setTimeout(function () {
$('.authent').hide();
$('.login').removeClass('test');
if (data.Status == 'ok') {
//登录成功
$('.login div').fadeOut(100);
$('.success').fadeIn(1000);
$('.success').html(data.Text);
//跳转操作
location.href = "Admin_index.aspx"
} else {
AjaxErro(data);
}
}, 2400);
})
}
})
})
var fullscreen = function () {
elem = document.body;
if (elem.webkitRequestFullScreen) {
elem.webkitRequestFullScreen();
} else if (elem.mozRequestFullScreen) {
elem.mozRequestFullScreen();
} else if (elem.requestFullScreen) {
elem.requestFullscreen();
} else {
//浏览器不支持全屏API或已被禁用
}
}
if (ajaxmockjax == 1) {
$.mockjax({
url: 'Ajax/Login',
status: 200,
responseTime: 50,
responseText: { "Status": "ok", "Text": "登陆成功<br /><br />欢迎回来" }
});
$.mockjax({
url: 'Ajax/LoginFalse',
status: 200,
responseTime: 50,
responseText: { "Status": "Erro", "Erro": "账号名或密码或验证码有误" }
});
}
</script>
<div class="layui-layer-move"></div>
</body>
</html>
登录API接口
namespace SW163WebClient.Controllers
{
/// <summary>
/// ==========2022-6-1(小金)===============
/// </summary>
public class UserController : ApiController
{
/// <summary>
/// 用户登录
/// </summary>
/// <param name="strUser"></param>
/// <param name="strPwd"></param>
/// <returns></returns>
[HttpGet]
public object Login(string strUser, string strPwd)
{
if (!ValidateUser(strUser, strPwd))
{
return new { bRes = false };
}
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, strUser, DateTime.Now,
DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", strUser, strPwd),
FormsAuthentication.FormsCookiePath);
//返回登录结果、用户信息、用户验证票据信息
var oUser = new UserInfo { bRes = true, UserName = strUser, Password = strPwd, Ticket = FormsAuthentication.Encrypt(ticket) };
//将身份信息保存在session中,验证当前请求是否是有效请求
//HttpContext.Current.Session[strUser] = oUser;
return oUser;
}
public void ProcessRequest(HttpContext context)
{
throw new NotImplementedException();
}
//校验用户名密码
private bool ValidateUser(string strUser, string strPwd)
{
SW163BLL.Administrators blladmin = new SW163BLL.Administrators();
DataTable dt = blladmin.GetList("UserName='" + strUser + "' and PassWord='" + SW163Common.DESEncrypt.Encrypt(strPwd) + "'").Tables[0];
if (dt.Rows.Count > 0)
{
return true;
}
else
{
return false;
}
}
}
public class UserInfo
{
public bool bRes { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Ticket { get; set; }
}
}
Home/Index.aspx界面
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace SW163WebClient.Admin { /// <summary> /// 2022-6-1 小金 /// </summary> public partial class Index: System.Web.UI.Page { public SW163UI.BasePage bg = new SW163UI.BasePage(); public string UserName = string.Empty; public string Ticket = string.Empty; public int first = 1; protected void Page_Load(object sender, EventArgs e) { HttpCookie myCookie = HttpContext.Current.Request.Cookies["Web"]; if (bg.CookieYESNo()) { Response.Redirect("Login.aspx"); } else { if (myCookie["UserName"] != null && myCookie["Ticket"] != null && myCookie["date"] != null) { UserName = myCookie["UserName"]; Ticket = myCookie["Ticket"]; //第一次登录时间和当前时间对比,大于30分钟清除cookie; DateTime time = Convert.ToDateTime(myCookie["date"]); DateTime time1 = DateTime.Now; TimeSpan timeSpan = time1 - time; if (timeSpan.TotalMinutes >= 30) { UserName = ""; Ticket = ""; bg.ExitCookie(); } else { //当前时间大于第一次登录时间1分钟,非第一次登录 if (Convert.ToDateTime(time1.ToString("yyyy-MM-dd HH:mm")) > Convert.ToDateTime(time.ToString("yyyy-MM-dd HH:mm"))) { first = 2; myCookie["Ticket"] = "2"; } } } else { bg.ExitCookie(); Response.Redirect("Login.aspx"); } } } //退出登录 protected void lbtnExit_Click(object sender, EventArgs e) { bg.ExitCookie(); } } }
<head>
<meta charset="utf-8">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
//打开页面的时候保存票据信息
var UserName ="<%=UserName %>";
var Ticket = "<%=Ticket%>";
var first =<%=first%>;
</script>
</head>
<script> $(function () { $.ajax({ type: "get", url: "/api/Charging/GetAllChargingData", data: {}, beforeSend: function (XHR) { //发送ajax请求之前向http的head里面加入验证信息 XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket); }, success: function (data, status) { if (status == "success") { if (first==1) { layer.alert(UserName + ":欢迎回家!"); } } }, error: function (e) { layer.alert("认证信息已过期!请重新登录", function () { //清除kooie $.ajax({ type: "post", url: "/Tools/Login.ashx", data: { "act":"clean_up"}, success: function (result) { window.location.href = "Login.aspx"; } }) }); }, complete: function () { } }); }); </script>
在WebAPI项目里面自定义一个类RequestAuthorizeAttribute,去继承AuthorizeAttribute这个类。然后重写OnAuthorization方法,在这个方法里面取到请求头的Ticket信息,再效验用户名和密码是否正确
/// <summary> /// ==========2022-6-1(小金)=============== /// 自定义此特性用于接口的身份验证 /// </summary> public class RequestAuthorizeAttribute : AuthorizeAttribute { //重写基类的验证方式,加入我们自定义的Ticket验证 public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) { //从http请求的头里面获取身份验证信息,验证是否是请求发起方的ticket var authorization = actionContext.Request.Headers.Authorization; if ((authorization != null) && (authorization.Parameter != null)) { //解密用户ticket,并校验用户名密码是否匹配 var encryptTicket = authorization.Parameter; if (ValidateTicket(encryptTicket)) { base.IsAuthorized(actionContext); } else { HandleUnauthorizedRequest(actionContext); } } //如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401 else { var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>(); bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute); if (isAnonymous) base.OnAuthorization(actionContext); else HandleUnauthorizedRequest(actionContext); } } //校验用户名密码 private bool ValidateTicket(string encryptTicket) { //解密Ticket var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData; //从Ticket里面获取用户名和密码 var index = strTicket.IndexOf("&"); string strUser = strTicket.Substring(0, index); string strPwd = strTicket.Substring(index + 1); SW163BLL.Administrators blladmin = new SW163BLL.Administrators(); DataTable dt = blladmin.GetList("UserName='" + strUser + "' and PassWord='" + SW163Common.DESEncrypt.Encrypt(strPwd) + "'").Tables[0]; if (dt.Rows.Count > 0) { return true; } else { return false; } } }
在具体的Api接口增加我们上面定义的自定义特性
/// <summary> /// ==========2022-6-1(小金)=============== /// </summary> public class ChargingController : BaseApiController { /// <summary> /// 得到所有数据 /// </summary> /// <returns>返回数据</returns> [HttpGet,Route("api/Charging/GetAllChargingData")] public string GetAllChargingData() { return "Success"; } /// <summary> /// 得到当前Id的所有数据 /// </summary> /// <param name="id">参数Id</param> /// <returns>返回数据</returns> [HttpGet, Route("api/Charging/GetAllChargingData")] public string GetAllChargingData(string id) { return "ChargingData" + id; } }
在API添加身份认证公共父类,子类只需继承父类认证即可
/// <summary> /// API 身份认证公共父类 /// /// ==========2022-6-1(小金)=============== /// /// origins配置允许访问的域名,多个域名以逗号分隔即可,域名一定要完整, /// 如果是ip地址前面要加上“http”,只使用IP的话一定会失效的。 /// 参数headers配置所支持的资源。 /// 参数methods配置支持的方法,get、post、put等。 /// 如果允许任意域名、任意资源、任意方法访问自己的webapi,则三个参数全部使用星号”*”即可 /// </summary> [RequestAuthorize] [EnableCors(origins: "*", headers: "*", methods: "*")] public class BaseApiController : ApiController { }
本文转自:https://www.cnblogs.com/landeanfen/p/5287064.html

浙公网安备 33010602011771号