最近折腾Cordova,希望能跟开发B/S项目一样开发一套APP程序,这样开发成本和维护成本以及学习成本可以降到最低;
之所以选择Cordova主要还是个人经历有限,不想去折腾Android和Ios开发了.自己陷入.NET比较深;
并且cordova又可以速成APP;如果不是做性能要求高的APP(比如游戏)其实是很推荐使用cordova.之前看到有调查显示混合APP占到了7成左右确实惊人!
基本上服务器端使用.NET MVC 5;技术主要是Rest API 交互;
客户端APP主要使用Cordova 使用Typescript生成javascript;用到了不少cordova的插件比如二维码扫描,定位之内的;
一开始架构以及开发环境进展都很顺利,但是最近发现一个问题.cordova需要调用服务器端需要授权的api接口的时候没办法做权限了.
因为cordova中没有cookie存储,并且就算有cookie也不能跨域,网上搜索了下 居然收不到.NET相关的解决方案;哎.只能说cordova生态不咋地;
而且.NET社区的cordova更不咋地了; 只能靠自己思考这个问题;
我的实现其实也简单,既然客户端不支持cookie那么HTML5的 localstore 或者sessionstore还是支持的吧.
另外jquery异步调用的时候 我们传递header头 服务器端通过header头判断用户信息不久可以了;思维还是很简单的;
首先从服务器端开刀:
实现自己的AuthorizeAttribute,代码如下:
namespace .....WebUI.Framework.Security { /// <summary> /// 用于移动端Cordova授权校验: /// </summary> public class CordovaAuthorizeAttribute : AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { var request = filterContext.RequestContext.HttpContext.Request; if (request.IsAuthenticated) { base.OnAuthorization(filterContext); return; } //使用header校验Cordova的安全 //xhr.setRequestHeader("username", ""); //xhr.setRequestHeader("password", ""); var username = request.Headers["username"]; var password = request.Headers["password"]; if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) { //用户信息无效 filterContext.Result = new HttpUnauthorizedJsonResult(); return; } try { //这里根据自己的业务代码获取用户在数据库中存储的内容. //为了性能这里可以加缓存. var svc = EngineContext.Current.Resolve<IMemberService>(); var user = svc.GetUserInfo(username, FindByType.ByUserName); if (user == null) { //无法查找到用户 filterContext.Result = new HttpUnauthorizedJsonResult(); return; } if (user.Status.GetValueOrDefault(0) != 1) { //用户已经被锁定 filterContext.Result = new HttpUnauthorizedJsonResult(); return; } var hasher = new PasswordHasher(); var flag = hasher.VerifyHashedPassword(user.PasswordHash, password); if (flag == PasswordVerificationResult.Failed) { //校验失败 filterContext.Result = new HttpUnauthorizedJsonResult(); return; } if (string.IsNullOrEmpty(Roles) && string.IsNullOrEmpty(Users)) { //成功: return; } if (string.IsNullOrEmpty(Roles) && Users.Split(new[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries).Contains(username, StringComparer.OrdinalIgnoreCase)) { //成功: return; } if (!string.IsNullOrEmpty(Roles)) { var userRoles = user.AspNetRoles.Select(a => a.Name).ToList(); foreach (var _role in Roles.Split(new[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries)) { foreach (var role in userRoles) { if (role.Equals(_role, StringComparison.OrdinalIgnoreCase)) { //成功: return; } } } } } catch { //用户名称错误等异常 //todo: } //校验失败: filterContext.Result = new HttpUnauthorizedJsonResult(); } } /// <summary> /// Json错误 /// </summary> internal class HttpUnauthorizedJsonResult : JsonResult { public override void ExecuteResult(ControllerContext context) { //避免Cordova调用后重定向 context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK; Data = new { status = (int)HttpStatusCode.Unauthorized }; JsonRequestBehavior = JsonRequestBehavior.AllowGet; base.ExecuteResult(context); } } }
服务器端代码搞定了.我们可以在我们的Action以及 Controller上面加上专供 cordova授权校验的 CordovaAuthorizeAttribute 属性头了.
比如:
[CordovaAuthorize(Roles="Admin")]
public ContentResult Test(string id)
{
return Content("Success");
}
cordova客户端调用服务器端API的代码就更简单了直接贴出来:
var url = "服务器端的地址"; $.ajax(url, { crossDomain: true, data: { rnd: Math.random() }, beforeSend: function (xhr) { //这里用户名和用户密码建议存储到sessionstore中. xhr.setRequestHeader("username", "用户名"); xhr.setRequestHeader("password", "用户密码"); }, success: function (data, status, req) { if (data.status && data.status==401) { //授权失败.那么根据自己的业务跳转到登陆页面吧: } //其他的status就根据自己的业务返回就可以了: }, error: function (error) { alert(JSON.stringify(error)); }, method: "GET", //根据自己的业务确定是POST还是GET complete: function () { alert("complete!"); }, timeout: 5000 });
然后棘手的问题就迎刃而解了;
如果考虑到客户端安全的话可以考虑密码加密.如果考虑到后端校验对数据库查询过于频繁可以考虑适当的使用缓存;
本人最近自学Cordova希望园子里面有志同道合之士共同探索研究!
最后任何问题都可以交流沟通 谢谢!