如何使用 Web API 来对 MVC 应用程序进行身份验证

 我来答
就烦条0o
2016-04-29 · 知道合伙人软件行家
就烦条0o
知道合伙人软件行家
采纳数:33315 获赞数:46492
从事多年系统运维,喜欢编写各种小程序和脚本。

向TA提问 私信TA
展开全部
首先,让我们先更新 API 项目

我们将先对 API 项目进行必要的修改,修改完成之后再切换到 Web 项目对客户端进行更新。

第1步:我们需要一个数据库

在能做任何操作之前我们需要先创建一个数据库。本例中将使用 SQL Server Express。如果你没有安装,可以从这里下载 SQL Server Express。安装完成之后,创建一个名为 CallingWebApiFromMvc 的数据库。这就是第一步要做的。

Api 项目还需要一个数据库连接字符串,否则我们寸步难行。把下面这段代码插入到 Api 项目的Web.config 文件中:

<connectionStrings>
<add name="ApiFromMvcConnection" connectionString="Data Source=(local);Initial Catalog=CallingWebApiFromMvc;Integrated 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 { get; set; }

[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
public string Password {
get; set;
}

[Required]
[Display(Name = "Confirm Password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}

控制器本身,如果注册成功只是返回一个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);
}
}
匿名用户
2016-04-29
展开全部
1 控制器基类ApiControllerBase
[csharp] view plaincopy

///
/// Controller的基类,用于实现适合业务场景的基础功能
///
///
[BasicAuthentication]
public abstract class ApiControllerBase : ApiController
{
}

2 权限属性BaseAuthenticationAttribute
[csharp] view plaincopy

///
/// 基本验证Attribtue,用以Action的权限处理
///
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
///
/// 检查用户是否有该Action执行的操作权限
///
///
public override void OnActionExecuting(HttpActionContext actionContext)
{
//检验用户ticket信息,用户ticket信息来自调用发起方
if (actionContext.Request.Headers.Authorization != null)
{
//解密用户ticket,并校验用户名密码是否匹配
var encryptTicket = actionContext.Request.Headers.Authorization.Parameter;
if (ValidateUserTicket(encryptTicket))
base.OnActionExecuting(actionContext);
else
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
else
{
//检查web.config配置是否要求权限校验
bool isRquired = (WebConfigurationManager.AppSettings["WebApiAuthenticatedFlag"].ToString() == "true");
if (isRquired)
{
//如果请求Header不包含ticket,则判断是否是匿名调用
var attr = actionContext.ActionDescriptor.GetCustomAttributes().OfType();
bool isAnonymous = attr.Any(a => a is AllowAnonymousAttribute);
//是匿名用户,则继续执行;非匿名用户,抛出“未授权访问”信息
if (isAnonymous)
base.OnActionExecuting(actionContext);
else
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
else
{
base.OnActionExecuting(actionContext);
}
}
}
///
/// 校验用户ticket信息
///
///
///
private bool ValidateUserTicket(string encryptTicket)
{
var userTicket = FormsAuthentication.Decrypt(encryptTicket);
var userTicketData = userTicket.UserData;
string userName = userTicketData.Substring(0, userTicketData.IndexOf(":"));
string password = userTicketData.Substring(userTicketData.IndexOf(":") + 1);
//检查用户名、密码是否正确,验证是合法用户
//var isQuilified = CheckUser(userName, password);
return true;
}
}

3 api服务Controller实例
[csharp] view plaincopy

public class ProductController : ApiControllerBase
{
[HttpGet]
public object Find(string id)
{
return ProductServiceInstance.Find(2);
}
// GET api/product/5
[HttpGet]
[AllowAnonymous]
public Product Get(string id)
{
var headers = Request.Headers;
var p = ProductServiceInstance.GetById(long.Parse(id));
if (p == null)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest)
Content = new StringContent("id3 not found"), ReasonPhrase = "product id not exist." });
}
return p;
}
}

4. 其它配置说明
1)、 Mvc前端Web.Config 配置
[html] view plaincopy

<</SPAN>system.web>
<</SPAN>compilation debug="true" targetFramework="4.5">
<</SPAN>assemblies>
<</SPAN>add assembly="System.Web.Http.Data.Helpers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</</SPAN>assemblies>
</</SPAN>compilation>
<</SPAN>httpRuntime targetFramework="4.5" />
<</SPAN>authentication mode="Forms">
<</SPAN>forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All" timeout="90" name=".AuthCookie"></</SPAN>forms>
</</SPAN>authentication>
<</SPAN>machineKey validationKey="3FFA12388DDF585BA5D35E7BC87E3F0AB47FBBEBD12240DD3BEA2BEAEC4ABA213F22AD27E8FAD77DCFEE306219691434908D193A17C1FC8DCE51B71A4AE54920" decryptionKey="ECB6A3AF9ABBF3F16E80685ED68DC74B0B13CCEE538EBBA97D0B893139683B3B" validation="SHA1" decryption="AES" />
</</SPAN>system.web>

machineKey节点配置,是应用于对用户ticket数据加密和解密。
2)、WebApi服务端Web.Config配置
[html] view plaincopy

<</SPAN>system.web>
<</SPAN>machineKey validationKey="3FF112388DDF585BA5D35E7BC87E3F0AB47FBBEBD12240DD3BEA2BEAEC4ABA213F22AD27E8FAD77DCFEE306219691434908D193A17C1FC8DCE51B71A4AE54920" decryptionKey="ECB6A3AF9ABBF3F16E80685ED68DC74B0B13CCEE538EBBA97D0B893139683B3B" validation="SHA1" decryption="AES" />
</</SPAN>system.web>

machineKey节点配置,是应用于对用户ticket数据加密和解密。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
兄弟连教育
2018-07-06 · 百度知道合伙人官方认证企业
兄弟连教育
兄弟连教育成立于2006年,11年来专注IT职业教育,是国内专业的IT技术培训学校。2016年成功挂牌新三板(股票代码:839467)市值过亿。开设专注程序员培训专注php、Java、UI、云计算、Python、HTML5、
向TA提问
展开全部
首先,让我们先更新 API 项目

我们将先对 API 项目进行必要的修改,修改完成之后再切换到 Web 项目对客户端进行更新。

第1步:我们需要一个数据库

在能做任何操作之前我们需要先创建一个数据库。本例中将使用 SQL Server Express。如果你没有安装,可以从这里下载 SQL Server Express。安装完成之后,创建一个名为 CallingWebApiFromMvc 的数据库。这就是第一步要做的。

Api 项目还需要一个数据库连接字符串,否则我们寸步难行。把下面这段代码插入到 Api 项目的Web.config 文件中:

<connectionStrings>
<add name="ApiFromMvcConnection" connectionString="Data Source=(local);Initial Catalog=CallingWebApiFromMvc;Integrated Security=True" providerName="System.Data.SqlClient" /></connectionStrings>
认证(Identity)框架会自动创建我们管理用户所需要的成员关系表,现在不需要担心去提前创建它们。
本回答被网友采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(1)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式