‘壹’ asp.net webapi 个人身份验证 token
重写AuthorizeAttribute,对你想要禁用的token抛出UnAuthorized
‘贰’ .net webAPI+NHibernate,调用get方法查询数据库的时候总是报错,"无效操作。连接被关闭。"
//Service.CreateSession();
很明显一些关键方法被屏蔽掉了,这里是创建session的,而且另外一个触发方法有事务提交的地方也被屏蔽了,建议你能打个断点调试下一切就明了了
‘叁’ WEBapi如何 去除 ASP.NET_SessionId 这个返回的Cookies啊
“被其他人截获到这个cookies岂不是可以做很多事了?”我认为未必,因为cookies是返回客户端的信息记录,其他人返回的是其他人的信息记录,不可能返回你的信息记录的。而且Session函数是仅仅返回你的客户端信息的,其他人不可能得到你的信息。
‘肆’ 登录系统时出现one or more errors occurred,怎么解决
one or more errors occurred(发生一个或多个错误)
1、建议开机检测硬件结束后,引导硬盘时,按住F8不放,在出现高级菜单时松开F8键,选择最近一次正确配置(高级)。
2、如果还是不行,插入 windows 安装盘(光盘、U盘均可)并重新启动计算机。
3、选择语言设置,然后单击“下一步”。
4、单击“修复计算机”。
5、如果修复安装后还是不行,请用原版系统安装盘全新安装。
‘伍’ visual studio 2008可以开发web api吗
usingSystem;usingSystem.Data;usingSystem.Configuration;usingSystem.Collections;usingSystem.Web;usingSystem.Web.Security;usingSystem.Web.UI;usingSystem.Web.UI.WebControls;usingSystem.Web.UI.WebControls.WebParts;usingSystem.Web.UI.HtmlControls;usingSystem.Data.SqlClient;publicpartialclassLogin:System.Web.UI.Page{protectedvoidPage_Load(objectsender,EventArgse){}protectedboolcheckText()//检验用户名输入字符,防止SQL注入{char[]a=txtNum.Text.ToCharArray();for(inti=0;ialert('验证码错误');location='Login.aspx'");//如果验证码错误,则将页面定位到登录界面}else{if(this.checkText()){if(this.ddlstatus.SelectedValue=="学生")//如果是学生登录,则调用BaseClass中的CheckStudent方法进行检验{//将用户输入的密码加密后与数据库中的值进行比较stringuser=txtNum.Text.Trim();stringpwd=BaseClass.md5(txtPwd.Text.Trim());if(BaseClass.CheckStudent(user,pwd))//如果通过验证,从数据库中查询出相关记录值保存,并将页面跳转到学生主界面{SqlConnectionconn=BaseClass.DBCon();conn.Open();SqlCommandcmd=newSqlCommand("select*fromStudentwhereStudentNum='"+txtNum.Text.Trim()+"'",conn);SqlDataReaderread=cmd.ExecuteReader();read.Read();//读取相关值显示考生姓名和性别stringstuName=read["StudentName"].ToString();conn.Close();//存储考生姓名和性别Session["name"]=stuName;Session["ID"]=txtNum.Text.Trim();//Response.Write("");Response.Redirect("student/StudentChose.aspx");}else//如果没有通过验证,弹出提示后定位到登录界面{Response.Write("");}}if(this.ddlstatus.SelectedValue=="教师")//如果是教师登录,则调用BaseClass中的CheckTeacher方法进行检验{//将用户输入的密码加密后与数据库中的值进行比较stringuser=txtNum.Text.Trim();stringpwd=BaseClass.md5(txtPwd.Text.Trim());if(BaseClass.CheckTeacher(user,pwd))//如果通过验证,保存相关记录值后将页面跳转到教师管理主界面{Session["Teacher"]=txtNum.Text;Response.Redirect("Teacher/TeacherManage.aspx");}else//如果没有通过验证,弹出提示后定位到登录界面{Response.Write("");}}}}}catch(Exceptionex){MessageBox.Show("不好意思,系统出错了,原因可能是:"+ex.Message);}}protectedvoidimgExit_Click(objectsender,ImageClickEventArgse){Response.Write("");}protectedvoidlkbtnAdminLogin_Click(objectsender,EventArgse){Response.Redirect("Admin/AdminLogin.aspx");//如果是管理员,则进入管理员登录界面}}
‘陆’ vue-resource 怎么解决跨域问题
上一篇我们介绍了如何使用vue resource处理请求,结合服务端的REST API,就能够很容易地构建一个增删查改应用。
这个应用始终遗留了一个问题,Web App在访问REST API时,没有经过任何认证,这使得服务端的REST API是不安全的,只要有人知道api地址,就可以调用API对服务端的资源进行修改和删除。
今天我们就来探讨一下如何结合Web API来限制资源的访问。
本文的主要内容如下:
介绍传统的Web应用和基于REST服务的Web应用
介绍OAuth认证流程和密码模式
创建一个基于ASP. Identity的Web API应用程序
基于$.ajax实现OAuth的注册、登录、注销和API调用
基于vue-resource实现OAuth的注册、登录、注销和API调用
本文的最终示例是结合上一篇的CURD,本文的登录、注册、注销和API调用功能实现的。
35
本文9个示例的源码已放到GitHub,如果您觉得本篇内容不错,请点个赞,或在GitHub上加个星星!
Page Demo GitHub Source
基于$.ajax的示例如下:
注册示例 登录和注销示例 登录获取token并调用API示例 注册、登录、注销、调用API综合示例
基于vue-resource的示例如下:
注册示例 登录和注销示例 登录获取token并调用API示例 注册、登录、注销、调用API综合示例
OAuth介绍
传统的Web应用
在传统的Web应用程序中,前后端是放在一个站点下的,我们可以通过会话(Session)来保存用户的信息。
例如:一个简单的ASP. MVC应用程序,用户登录成功后,我们将用户的ID记录在Session中,假设为Session["UserID"]。
前端发送ajax请求时,如果这个请求要求已登录的用户才能访问,我们只需在后台Controller中验证Session["UserID"]是否为空,就可以判断用户是否已经登录了。
这也是传统的Web应用能够逃避面向无连接的方法。
基于REST服务的Web应用
当今很多应用,客户端和服务端是分离的,服务端是基于REST风格构建的一套Service,客户端是第三方的Web应用,客户端通过跨域的ajax请求获取REST服务的资源。
然而REST Service通常是被设计为无状态的(Stateless),这意味着我们不能依赖于Session来保存用户信息,也不能使用Session["UserID"]这种方式确定用户身份。
解决这个问题的方法是什么呢?常规的方法是使用OAuth 2.0。
对于用户相关的OpenAPI,为了保护用户数据的安全和隐私,第三方Web应用访问用户数据前都需要显式的向用户征求授权。
相比于OAuth 1.0,OAuth 2.0的认证流程更加简单。
专用名词介绍
在了解OAuth 2.0之前,我们先了解几个名词:
Resource:资源,和REST中的资源概念一致,有些资源是访问受保护的
Resource Server:存放资源的服务器
Resource Owner:资源所有者,本文中又称为用户(user)
User Agent:用户代理,即浏览器
Client: 访问资源的客户端,也就是应用程序
Authorization Server:认证服务器,用于给Client提供访问令牌的服务器
Access Token:访问资源的令牌,由Authorization Server器授予,Client访问Resource时,需提供Access Token
Bearer Token:Bearer Token是Access Token的一种,另一种是Mac Token。
Bearer Token的使用格式为:Bearer XXXXXXXX
Token的类型请参考:s://tools.ietf/html/draft-ietf-oauth-v2-15#section-7.1
有时候认证服务器和资源服务器可以是一台服务器,本文中的Web API示例正是这种运用场景。
OAuth认证流程
在知道这几个词以后,我们用这几个名词来编个故事。
简化版本
这个故事的简化版本是:用户(Resource Owner)访问资源(Resource)。
image
具体版本
简化版的故事只有一个结果,下面是这个故事的具体版本:
用户通过浏览器打开客户端后,客户端要求用户给予授权。
客户端可以直接将授权请求发给用户(如图所示),或者发送给一个中间媒介,比如认证服务器。
用户同意给予客户端授权,客户端收到用户的授权。
授权模式(Grant Type)取决于客户端使用的模式,以及认证服务器所支持的模式。
客户端提供身份信息,然后向认证服务器发送请求,申请访问令牌
认证服务器验证客户端提供的身份信息,如果验证通过,则向客户端发放令牌
客户端使用访问令牌,向资源服务器请求受保护的资源
资源服务器验证访问令牌,如果有效,则向客户端开放资源
image
以上几个步骤,(B)是较为关键的一个,即用户怎么样才能给客户端授权。有了这个授权以后,客户端就可以获取令牌,进而通过临牌获取资源。这也是OAuth 2.0的运行流程,详情请参考:s://tools.ietf/html/draft-ietf-oauth-v2-15#section-1.2
客户端的授权模式
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。
OAuth 2.0定义了四种授权方式:
授权码模式(authorization code)
简化模式(implicit)
密码模式(resource owner password credentials)
客户端模式(client credentials)
本文的示例是基于密码模式的,我就只简单介绍这种模式,其他3我就不介绍了,大家有兴趣可以看阮大的文章:
://http://www.yingtaow.com/sitemap.html?blog/2014/05/oauth_2_0.html
密码模式
密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向服务端申请授权。
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个着名公司出品。
image
密码嘛事的执行步骤如下:
(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
(C)认证服务器确认无误后,向客户端提供访问令牌。
(B)步骤中,客户端发出的请求,包含以下参数:
grant_type:表示授权类型,此处的值固定为"password",必选项。
username:表示用户名,必选项。
password:表示用户的密码,必选项。
scope:表示权限范围,可选项。
注意:在后面的客户端示例中,除了提供username和password,grant_type也是必须指定为"password",否则无法获取服务端的授权。
服务端环境准备
如果您是前端开发人员,并且未接触过ASP. Web API,可以跳过此段落。
image
Authentication选择Indivial User Accounts
image
创建这个Web API工程时,VS会自动引入Owin和Asp.Identity相关的库。
image
修改ValuesController,除了IEnumerable<string> Get()操作外,其他操作都删除,并为该操作应用[Authorize]特性,这表示客户端必须通过身份验证后才能调用该操作。
public class ValuesController : ApiController
{
// GET: api/Values
[Authorize]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
添加Model, Controller
image
image
image
初始化数据库
image
执行以下3个命令
image
image
执行以下SQL语句:
显示代码
CustomersController类有5个Action,除了2个GET请求外,其他3个请求分别是POST, PUT和DELETE。
为这3个请求添加[Authorize]特性,这3个请求必须通过身份验证才能访问。
隐藏代码
public class CustomersController : ApiController
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: api/Customers
public IQueryable<Customer> GetCustomers()
{
return db.Customers;
}
// GET: api/Customers/5
[ResponseType(typeof(Customer))]
public async Task<IActionResult> GetCustomer(int id)
{
Customer customer = await db.Customers.FindAsync(id);
if (customer == null)
{
return NotFound();
}
return Ok(customer);
}
// PUT: api/Customers/5
[Authorize]
[ResponseType(typeof(void))]
public async Task<IActionResult> PutCustomer(int id, Customer customer)
{
// ...
}
// POST: api/Customers
[Authorize]
[ResponseType(typeof(Customer))]
public async Task<IActionResult> PostCustomer(Customer customer)
{
// ...
}
// DELETE: api/Customers/5
[ResponseType(typeof(Customer))]
[Authorize]
public async Task<IActionResult> DeleteCustomer(int id)
{
// ...
}
}
让Web API以CamelCase输出JSON
在Global.asax文件中添加以下几行代码:
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new ();
启用CORS
在Nuget Package Manager Console输入以下命令:
Install-Package Microsoft.Asp.WebApi.Cors
在WebApiConfig中启用CORS:
public static class WebApiConfig
{
public static void Register(Configuration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
// ...
}
}
类说明
在执行上述步骤时,VS已经帮我们生成好了一些类
image
IdentityModels.cs:包含ApplicationDbContext类和ApplicationUser类,无需再创建DbContext类
public class ApplicationUser : IdentityUser
{
// ...
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
// ...
}
Startup.Auth.cs:用于配置OAuth的一些属性。
public partial class Startup
{
public static OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit ://go.microsoft./fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// ..
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In proction mode set AllowInsecure = false
AllowInsecure = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
// ..
}
}
这些OAuth配置项,我们只用关注其中的两项:
TokenEndpointPath:表示客户端发送验证请求的地址,例如:Web API的站点为www.example.,验证请求的地址则为www.example./token。
UseOAuthBearerTokens:使用Bearer类型的token_type(令牌类型)。
ApplicationOAuthProvider.cs:默认的OAuthProvider实现,GrantResourceOwnerCredentials方法用于验证用户身份信息,并返回access_token(访问令牌)。
public override async Task GrantResourceOwnerCredentials( context)
{
// ...
}
通俗地讲,客户端输入用户名、密码,点击登录后,会发起请求到www.example./token。
token这个请求在服务端执行的验证方法是什么呢?正是GrantResourceOwnerCredentials方法。
客户端发起验证请求时,必然是跨域的,token这个请求不属于任何ApiController的Action,而在WebApiConfig.cs中启用全局的CORS,只对ApiController有效,对token请求是不起作用的。
所以还需要在GrantResourceOwnerCredentials方法中添加一行代码:
public override async Task GrantResourceOwnerCredentials( context)
{
context.Response.Headers.Add("Access-Control-Allow-Origin", new []{"*"});
// ...
}
IdentityConfig.cs:配置用户名和密码的复杂度,主要用于用户注册时。例如:不允许用户名为纯字母和数字的组合,密码长度至少为6位…。
隐藏代码
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
= false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// ...
return manager;
}
使用Postman测试GET和POST请求
测试GET请求
image
GET请求测试成功,可以获取到JSON数据。
测试POST请求
image
POST请求测试不通过,提示:验证不通过,请求被拒绝。
基于$.ajax实现注册、登录、注销和API调用
服务端的环境已经准备好了,现在我们就逐个实现用户注册、登录,以及API调用功能吧。
注册
页面的HTML代码如下:
<div id="app">
<div class="container">
<span id="message">{{ msg }}</span>
</div>
<div class="container">
<div class="form-group">
<label>电子邮箱</label>
<input type="text" v-model="registerModel.email" />
</div>
<div class="form-group">
<label>密码</label>
<input type="text" v-model="registerModel.password" />
</div>
<div class="form-group">
<label>确认密码</label>
<input type="text" v-model="registerModel.confirmPassword" />
</div>
<div class="form-group">
<label></label>
<button @click="register">注册</button>
</div>
</div>
</div>
创建Vue实例,然后基于$.ajax发送用户注册请求:
var demo = new Vue({
el: '#app',
data: {
registerUrl: '://localhost:10648/api/Account/Register',
registerModel: {
email: '',
password: '',
confirmPassword: ''
},
msg: ''
},
methods: {
register: function() {
var vm = this
vm.msg = ''
$.ajax({
url: vm.registerUrl,
type: 'POST',
dataType: 'json',
data: vm.registerModel,
success: function() {
vm.msg = '注册成功!'
},
error: vm.requestError
})
},
requestError: function(xhr, errorType, error) {
‘柒’ c# webapi Session
没使用过,
既然你的程序被设计为 webapi,或者SOA架构,你应该抛弃这种设计,让第三方库 缓存 或者 本地缓存 做为验证保存。如果是设计为分布式,你需要一个中央缓存管理这些信息,
‘捌’ ashx什么时候执行 processrequest
ASP.NET中HttpApplication中ProcessRequest方法中执行的事件顺序
1.BeginRequest 开始处理请求
2.AuthenticateRequest 授权验证请求,获取用户授权信息
3.PostAuthenticateRequest 获取成功
4.AunthorizeRequest 授权,一般来检查用户是否获得权限
5.PostAuthorizeRequest 获得授权
6.ResolveRequestCache 获取页面缓存结果(如果没有则执行)
7.PostResolveRequestCache 已获取缓存
8.PostMapRequestHandler 创建页面对象
9.AcquireRequestState 获取Session -- 先判断当前页面对象是否实现了IRequiresSessionState接口,如果实现了,则从浏览器发来的请求报文头中获得SessionId,并到服务器的 Session池中获得对应的Session对象,最后赋值给 HttpContext的Session属性。
10.PostAcquireRequestState 获得Session
11.PreRequestHandlerExecute 准备执行页面对象
×执行页面对象的ProcessRequest方法(1.ashx,1.aspx),如果请求的是1.aspx,则会运行页面生命周期
12.PostRequestHandlerExecute 执行完页面对象了
13.ReleaseRequestState 释放请求状态
14.PostReleaseRequestState 已释放请求状态
15.UpdateReuqestCache 更新缓存
16.PostUpdateRequestCache 已更新缓存
17.LogRequest 日志记录
18.PostLogRequest 已完成日志
19.EndRequest 完成
可以再Global.asax中添加以Application_为前缀+事件名 的方法运行测试!例如:
[csharp] view plain
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
public void Application_BeginRequest(object sender, EventArgs e)
{
HttpApplication obj = sender as HttpApplication;
obj.Context.Response.Write("1 Application_BeginRequest<br/>");
}
public void Application_ResolveRequestCache(object sender, EventArgs e)
{
HttpApplication obj = sender as HttpApplication;
obj.Context.Response.Write("6 Application_ResolveRequestCache<br/>");
}
public void Application_PostResolveRequestCache(object sender, EventArgs e)
{
HttpApplication obj = sender as HttpApplication;
obj.Context.Response.Write("7 Application_PostResolveRequestCache<br/>");
}
public void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication obj = sender as HttpApplication;
obj.Context.Response.Write("11 Application_PreRequestHandlerExecute<br/>");
}
}
以下附上MVC整体请求流程图,来自传智播客黑马培训班
ASP.net WebForm整体请求流程图,来自传智播客黑马培训班