我们将先对 API 项目进行必要的修改,修改完成之后再切换到 Web 项目对客户端进行更新。
第1步:我们需要一个数据库
在能做任何 *** 作之前我们需要先创建一个数据库。本例中将使用 SQL Server Express。如果你没有安装,可以从这里下载 SQL Server Express。安装完成之后,创建一个名为 CallingWebApiFromMvc 的数据库。这就是第一步要做的。
Api 项目还需要一个数据库连接字符串,否则我们寸步难行。把下面这段代码插入到 Api 项目的Web.config 文件中:
<connectionStrings>
<add name="ApiFromMvcConnection" connectionString="Data Source=(local)Initial Catalog=CallingWebApiFromMvcIntegrated Security=True" providerName="System.Data.SqlClient" /></connectionStrings>
认证(Identity)框架会自动创建我们管理用户所需要的成员关系表,现在不需要担心去提前创建它们。
第2步:添加相关的Nuget包
接下来我们添加用于OWIN和Windows认证的Nuget包。打开包管理控制台,切换Api项目为缺省项目,输入以下命令:
Install-Package Microsoft.AspNet.WebApi.Owin
Install-Package Microsoft.Owin.Host.SystemWeb
Install-Package Microsoft.AspNet.Identity.EntityFramework
Install-Package Microsoft.AspNet.Identity.Owin
使用这些包可以在我们的应用中启动一个OWIN服务器,然后通过EntityFramework把我们的用户保存到SQL Server。
第3步:添加管理用户的Identity类
我们使用基于Windows认证机制之上的Entity框架来管理数据库相关的业务。首先我们需要添加一些用于处理的类。在Api项目里添加一个Identity目录作为我们要添加类的命名空间。然后添加如下的类:
public class ApplicationUser : IdentityUser
{
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{public ApplicationDbContext() : base("ApiFromMvcConnection") {}
public static ApplicationDbContext Create()
{return new ApplicationDbContext()
}
}
注意我们传给基类构造函数的参数ApiFromMvcConnection要和Web.config中的连接字符串中的name相匹配。
public class ApplicationUserManager : UserManager<ApplicationUser>
{public ApplicationUserManager(IUserStore<ApplicationUser>store) : base(store)
{
}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)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
}
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
} var dataProtectionProvider = options.DataProtectionProvider
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
}return manager
}
}
第4步:添加OWIN启动类
为了让我们的应用程序作为OWIN服务器上运行,我们需要在应用程序启动时初始化。我们可以通过一个启动类做到这一点。我们将装点这个类的
OwinStartup属性,因此在应用程序启动时触发。这也意味着,我们可以摆脱的Global.asax和移动它们的
Application_Start代码转换成我们新的启动类。
using Microsoft.Owin
[assembly: OwinStartup(typeof(Levelnis.Learning.CallingWebApiFromMvc.Api.Startup))]
namespace Levelnis.Learning.CallingWebApiFromMvc.Api
{
using System
using System.Web.Http
using Identity
using Microsoft.Owin.Security.OAuth
using Owin
using Providers
public class Startup
{public void Configuration(IAppBuilder app)
{
GlobalConfiguration.Configure(WebApiConfig.Register)
app.CreatePerOwinContext(ApplicationDbContext.Create)
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create) var oAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/api/token"),
Provider = new ApplicationOAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
AllowInsecureHttp = true
}
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(oAuthOptions)
}
}
}
在应用程序启动时,我们正在建立自己的服务器。在这里,我们配置令牌端点并设置自己的自定义提供商,我们用我们的用户进行身份验证。在我们的例子中,我们使用了ApplicationOAuthProvider类。让我们来看看现在:
第5步:添加OAuth的提供商
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated()
return Task.FromResult<object>(null)
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>()
var user = await userManager.FindAsync(context.UserName, context.Password)
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.") return
}
var oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType) var cookiesIdentity = await user.GenerateUserIdentityAsync(userManager, CookieAuthenticationDefaults.AuthenticationType) var properties = CreateProperties(user.UserName) var ticket = new AuthenticationTicket(oAuthIdentity, properties)
context.Validated(ticket)
context.Request.Context.Authentication.SignIn(cookiesIdentity)
}
private static AuthenticationProperties CreateProperties(string userName)
{
var data = new Dictionary<string, string>
{
{
"userName", userName
}
}
return new AuthenticationProperties(data)
}
}
我们感兴趣的是这里2种方法。第一,ValidateClientAuthentication,只是验证客户端。我们有一个客户端,所以返回成
功。这是一个异步方法签名但没有异步调用发生。正因为如此,我们可以离开了异步修改,但我们必须返回一个任务自己。我们增加了一个名为
GenerateUserIdentityAsync的ApplicationUser,它看起来像这样的方法:
public class ApplicationUser : IdentityUser
{public async Task<ClaimsIdentity>GenerateUserIdentityAsync(UserManager<ApplicationUser>manager, string authenticationType)
{
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType)
return userIdentity
}
}
第6步:注册一个新用户 - API端
所以,我们有到位的所有Identity类管理用户。让我们来看看RegisterController,将新用户保存到我们的数据库。它接受一个RegisterApi模式,这是简单的:
public class RegisterApiModel
{
[Required]
[EmailAddress]public string Email { getset}
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
public string Password {
getset
}
[Required]
[Display(Name = "Confirm Password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { getset}
}
控制器本身,如果注册成功只是返回一个200 OK响应。如果验证失败,则返回401错误请求的响应。
public class RegisterController : ApiController
{private ApplicationUserManager UserManager
{get
{return Request.GetOwinContext().GetUserManager<ApplicationUserManager>()
}
}public IHttpActionResult Post(RegisterApiModel model)
{if (!ModelState.IsValid)
{return BadRequest(ModelState)
}var user = new ApplicationUser
{
Email = model.Email,
UserName = model.Email,
EmailConfirmed = true
}
var result = UserManager.Create(user, model.Password)
return result.Succeeded ? Ok() : GetErrorResult(result)
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
{
return InternalServerError()
}
if (result.Errors != null)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error)
}
}
if (ModelState.IsValid)
{
// No ModelState errors are available to send, so just return an empty BadRequest.
return BadRequest()
}
return BadRequest(ModelState)
}
}
这几天小明又有烦恼了,之前给小红的接口没有做认证授权,直接裸奔在线上,被马老板发现后狠狠的骂了一顿,赶紧让小明把授权加上。赶紧Baidu一下,发现大家都在用JWT认证授权,这个倒是挺适合自己的。
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
从图中可以看出主要有两部分组成:1、获取Token,2、通过Token进行授权。
首先 ,安装JwtBearer包。
接下来 ,定义一个配置类,我这里为了简单直接用常量代替了,你也可以放在配置文件中。
接下来 ,定义一个通过用户名和密码,获取Token的控制器。
接下来 ,添加Token身份认证到容器(Startup.ConfigureServices)。
接下来 ,添加身份认证到中间件(Startup.Configure)。
接下来 ,控制器需要授权控制的添加[Authorize]。
最后 ,我们测试一下接口,效果如下。
这时会返回401,因为身份认证没有通过,说明身份验证起效果了。
接下来我们访问一下GetAccessToken接口,拿到Token,在访问GetTodo接口时放入Token,我们可以看到访问成功了。
目前为止,小明把授权认证搞定了,赶紧给马老板汇报工作去吧。当然这个授权认证还是非常简单的,还有很多等待的小伙伴们去发掘,比如如何自动刷新Token?如何强制Token失效?OAuth其他实现方式等等?大家如果有兴趣,让小明下次告诉你们。
有以下限制,1.必须在微信打开
2.微信页面授权
其中第一步比较容易实现,修改下ua(user-agent),让其携带“MicroMessenger”字段即可。
第二部则是由于微信浏览器内置一些js库,在其他浏览器是无内置的,所以在chrome网页授权基本是无效的。不过可以用其他办法略过授权。
解决方案:1、是伪装微信浏览器,使其绕过微信验证,2、获取cookie,跳过授权验证。
2、 准备工具
1.chrome,主要是用于修改user-agent.
2.fiddler抓包工具(安装正式抓取https包)
一,修改UA
打开Chrome浏览器,按下F12进入手机调试模式
选择Edit
点击Add custom device
输入ua,UA通过fiddler抓包获取
我的 User-Agent是: Mozilla/5.0 (LinuxAndroid 6.0vivo Y67A Build/MRA58Kwv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043508 Safari/537.36 MicroMessenger/6.5.13.1100 NetType/WIFI Language/zh_CN
可以直接使用这个UA,也可以抓取自己的ua
第二步,添加cookie
fiddler抓取cookie
在console下面输入 document.cookie=“(cookie通过抓包获取)”,后回车
打开Chrome可以看到,我添加的cookie成功
chrome打开地址,不会报错啦
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)