WebAPI主要开放数据给手机APP,其余须要得知数据的系统,或者软件应用,因此移动端与系统的数据源每每是相通的。html
Web 用户的身份验证,及页面操做权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,经过角色受权来控制用户访问前端
本文经过Basic 方式进行基础认证Mvc的Controller基类及Action的权限验证来实现Web系统登陆,Mvc前端权限校验以及WebApi服务端的访问校验功能,本文主要做为本人备忘使用,如能给予人帮助,深感荣幸,欢迎讨论和指正,下面梳理一下验证的流程jquery
VS2015+无数据库(模拟数据)web
1.WebApi服务端接收访问请求,须要作安全验证处理,验证处理步骤具体以下:ajax
1) 若是是合法的Http请求,在Http请求头中会有用户身份的票据信息(若是是跨域那么没法在请求头中添加票据),服务端会读取票据信息,并校验票据信息是否完整有效,若是知足校验要求,则进行业务数据的处理,并返回给请求发起方;数据库
2) 若是没有票据信息,或者票据信息不是合法的,则返回“未受权的访问”异常消息给前端,由前端处理此异常。json
2. 登陆及权限验证流程api
1) 用户打开浏览器,并在地址栏中输入页面请求地址,提交;跨域
2) 浏览器解析Http请求,发送到Web服务器;Web服务器验证用户请求,首先判断是否有登陆的票据信息;浏览器
3) 用户没有登陆票据信息,则跳转到登陆页面;
4) 用户输入用户名和密码信息;
5) 浏览器提交登陆表单数据给Web服务器;
6) Web服务须要验证用户名和密码是否匹配,发送api请求给api服务器;
7) api用户帐户服务根据用户名,读取存储在数据库中的用户资料,判断密码是否匹配;
7.1)若是用户名和密码不匹配,则提示密码错误等信息,然该用户从新填写登陆资料;
7.2)若是验证经过,则保存用户票据信息;
8)
3.若是用户有登陆票据信息,则跳转到用户请求的页面;
9) 验证用户对当前要操做的页面或页面元素是否有权限操做,首先须要发起api服务请求,获取用户的权限数据;
10). api用户权限服务根据用户名,查找该用户的角色信息,并计算用户权限列表,封装为Json数据并返回;
11). 当用户有权限操做页面或页面元素时,跳转到页面,并由页面Controller提交业务数据处理请求到api服务器; 若是用户没有权限访问该页面或页面元素时,则显示“未受权的访问操做”,跳转到系统异常处理页面。
12). api业务服务处理业务逻辑,并将结果以Json 数据返回;
13). 返回渲染后的页面给浏览器前端,并呈现业务数据到页面;
14). 用户填写业务数据,或者查找业务数据;
15). 当填写或查找完业务数据后,用户提交表单数据;
16). 浏览器脚本提交get,post等请求给web服务器,由web服务器再次解析请求操做,重复步骤2的后续流程;
17). 当api服务器验证用户身份是,没有可信用户票据,系统提示“未受权的访问操做”,跳转到系统异常处理页面。
using Apps.Common; using Apps.WebApi.Models; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web; using System.Web.Http; using System.Web.Security; namespace Apps.WebApi.Controllers { public class AccountController : ApiController { [HttpGet] public object Login(string userName, string password) { //实际场景应该到数据库进行校验 if (userName != "123" && password!="123") { return Json(JsonHandler.CreateMessage(0, "用户名或密码错误")); } FormsAuthenticationTicket token = new FormsAuthenticationTicket(0, userName, DateTime.Now, DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", userName, password), FormsAuthentication.FormsCookiePath); //返回登陆结果、用户信息、用户验证票据信息 var Token = FormsAuthentication.Encrypt(token); //将身份信息保存在session中,验证当前请求是不是有效请求 HttpContext.Current.Session[userName] = Token; return Json(JsonHandler.CreateMessage(1, Token)); } } }
对用户名和密码进行校验,这里没有数据库演示,因此直接是进行固定匹配,账号123,密码123(可参考19节用户登陆,得到数据库的校验方式)
登陆失败:返回错误提示
登陆成功:返回Token并保存Token到 Session
可见代码中包含Session的操做,可是Webapi默认是不支持Session的,因此咱们须要在Global加载时候添加对Session的支持,否则运行调用会直接异常
protected void Application_PostAuthorizeRequest()
{
HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
}
输入http://localhost:13743/help能够看到,咱们的接口已经在webapi help列出,并能够查看调用方式(VS2012可能没有自动生成WebApi Help,须要从Nuget包得到)
在Home的Index.cshtm添加登陆代码
<script src="~/Scripts/jquery-1.10.2.min.js"></script> <style>html,body{height:100%}.box{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#6699FF', endColorstr='#6699FF');background-image:linear-gradient(bottom,#69F 0,#69F 100%);background-image:-o-linear-gradient(bottom,#69F 0,#69F 100%);background-image:-moz-linear-gradient(bottom,#69F 0,#69F 100%);background-image:-webkit-linear-gradient(bottom,#69F 0,#69F 100%);background-image:-ms-linear-gradient(bottom,#69F 0,#69F 100%);margin:0 auto;position:relative;width:100%;height:100%}.login-box{width:100%;max-width:500px;height:400px;position:absolute;top:50%;margin-top:-200px}@@media screen and (min-width:500px){.login-box{left:50%;margin-left:-250px}}.form{width:100%;max-width:500px;height:275px;margin:25px auto 0 auto;padding-top:25px}.login-content{height:300px;width:100%;max-width:500px;background-color:rgba(255,250,2550,.6);float:left}.input-group{margin:0 0 30px 0!important}.form-control,.input-group{height:40px}.form-group{margin-bottom:0!important}.login-title{padding:20px 10px;background-color:rgba(0,0,0,.6)}.login-title h1{margin-top:10px!important}.login-title small{color:#fff}.link p{line-height:20px;margin-top:30px}.btn-sm{padding:8px 24px!important;font-size:16px!important} </style> <div class="box" style="margin:100px;height:400px;width:500px;"> <div class="login-box"> <div class="login-title text-center"> <h1><small>登陆</small></h1> </div> <div class="login-content "> <div class="form"> <form action="#" method="post"> <div class="form-group"> <div class="col-xs-12 "> <div class="input-group"> <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> <input type="text" id="username" name="username" class="form-control" placeholder="用户名"> </div> </div> </div> <div class="form-group"> <div class="col-xs-12 "> <div class="input-group"> <span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span> <input type="text" id="password" name="password" class="form-control" placeholder="密码"> </div> </div> </div> <div class="form-group form-actions"> <div class="col-xs-4 col-xs-offset-4 "> <button type="button" id="Login" class="btn btn-sm btn-info"><span class="glyphicon glyphicon-off"></span> 登陆</button> </div> </div> </form> </div> </div> </div> </div> <script> $(function () { $("#Login").click(function () { $.ajax({ type: "get", url: "/api/Account/Login", data: { userName: $("#username").val(), password: $("#password").val() }, success: function (data, status) { if (data.type==0) { alert("登陆失败"); return; } alert("登陆成功:Token"+data.message); }, error: function (e) { alert("登陆失败!"); }, complete: function () { } }); }); }); </script>
浏览器中运行/Home/Index
成功取得Token
同域名访问,通常系统任务这是安全的,能够信任的,因此不须要作过多的考虑,这是咱们来看看跨域的状况
把8866的Home/index登陆界面代码复制到4455下的Home/index,修改访问URL
url: "http://localhost:8866/api/Account/Login"
这样才用让4455去访问6655的API,否则绝对报404
访问成功,可是没有返回值,jquery显示jquery的jsonp格式有callback返回
设置Ajax的dataType 为Jsonp
dataType:"jsonp",
再次运行,带回来的值正常
可是结果并无弹出token并提示一个js错误
到这里真是一波三折
由于返回的值是:{"Id":"123"}
然而Jsonp须要你返回:jQuery*([{"Id":123"}])
注册一个全局属性
using System.Net.Http; using System.Text; using System.Web; using System.Web.Http.Filters; namespace Apps.WebApi.Core { public class JsonCallbackAttribute : ActionFilterAttribute { private const string CallbackQueryParameter = "callback"; public override void OnActionExecuted(HttpActionExecutedContext context) { var callback = string.Empty; if (IsJsonp(out callback)) { var jsonBuilder = new StringBuilder(callback); jsonBuilder.AppendFormat("({0})", context.Response.Content.ReadAsStringAsync().Result); context.Response.Content = new StringContent(jsonBuilder.ToString()); } base.OnActionExecuted(context); } private bool IsJsonp(out string callback) { callback = HttpContext.Current.Request.QueryString[CallbackQueryParameter]; return !string.IsNullOrEmpty(callback); } } }
GlobalConfiguration.Configuration.Filters.Add(new JsonCallbackAttribute());
再次运行:
本节结束,下节再学习怎么利用Token进行访问得到权限
参考资料:
http://stackoverflow.com/questions/9594229/accessing-session-using-asp-net-web-api
http://stackoverflow.com/questions/23698804/asp-net-mvc-with-forms-auth-and-webapi-with-basic-auth
https://weblog.west-wind.com/posts/2013/apr/18/a-webapi-basic-authentication-authorization-filter
http://stackoverflow.com/questions/17121964/asp-net-web-api-restful-web-service-basic-authentication
http://www.cnblogs.com/Kummy/p/3767269.html
实例代码下载 访问密码 13df