我正在使用 Web api 和 Angular js 创建 1 个网站,我对在我的网站中使用的身份验证感到非常困惑。
我创建了一个 login.js,其中有一个登录方法,它将把我的用户名/电子邮件 ID 和密码发布到我的 Web Api,并且 Web api 中的方法将验证该用户。
代码:
$scope.Login()
{
$.post("api/Authentication/Login",Username,Password)
{
}
}
Web API 代码:
[Route]
Public Task<object> Login([FromBody] username,password)
{
//method to authenticate user from database.
//Now the tricky parts comes like after authenticating user should i
//just store the user id in my session like this Session["userid]=id or
//Should i go for storing whole user object in my cookie as i have read
//that storing data in session is very bad idea and disaster too as session is very memory
//and so i think i would go for cookie which will be saved on client side.
//but what if cookie isnt supported by browser??
}
正如 Darin Dimitrov 在他的回答和评论中指出的那样,使用会话是灾难。 因此,我决定根据此答案使用 cookie,并且其中一个电子商务网站 Nop Commerce 也根据此问题和答案使用 cookie 来存储当前登录的客户对象问题
我遵循LukeP在这个Question中建议的代码用于身份验证目的,并在整个应用程序中维护当前的登录用户对象。
我也读过有关 asp.net 声明身份的内容,但不知道是否可以在我的 asp.net Web api 和 Angular js 中使用它。
那么任何人都可以告诉我在 asp.net Web api 和 Angular JS 中进行身份验证的正确方法是什么,以及在 LukeP 代码中要完成哪些更改才能使用 Web api 和 Angular JS??
任何人都可以向我解释一下我上面指出的这个方法,并提供一些详细描述和一些代码,因为它可以帮助我和其他一些人,如果他们正在寻找相同的东西。
稍后我将为解决上述所有代码问题的答案提供 100 赏金。
最好的方法是使用令牌身份验证。总而言之,它的工作原理如下:
POST /api/login
路由接受用户名 + 密码,检查它们对于数据库是否有效,然后生成并返回
refresh token
(可以是随机字符串或 GUID)。
refresh token
也存储在用户旁边的数据库中,覆盖之前的
refresh token
服务器上的 GET /api/access-token
refresh token
,检查它们在数据库中是否匹配,然后生成并返回 access token
任何其他/api/*
access token
,否则它们会假设用户没有有效的登录
access token
是使用只有服务器知道的密钥加密的数据对象。它应包含用户名、到期日期(通常从生成令牌后约 10 分钟)以及有关用户的任何权限或其他数据。因为它是用密钥加密的,所以攻击者无法伪造。
您需要在您的服务器上实现这些路由。
如果您使用 OWIN,则可以使用以下方法使用
Microsoft.Owin.Security.OAuth
NuGet 包为您进行加密:
将其添加到您的启动配置中:
using System.Web.Http;
using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using Owin;
[assembly: OwinStartup(typeof(MyProject.Startup))]
namespace MyProject
{
public class Startup
{
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
app.UseWebApi(config);
}
}
}
然后,你可以生成一个
ticket
(即未加密的
access token
)并像这样加密它:var identity = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Email, "users email"),
// other business specific claims e.g. "IsAdmin"
});
var ticket = new AuthenticationTicket(identity, new AuthenticationProperties(
{
ExpiresUtc = DateTime.UtcNow.AddMinutes(10)
}));
var accessToken = MyProject.Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
在 Angular 中,您需要设置一种登录方式、一种在过期时获取新
access token
的方式,以及一种在每个 API 请求的标头中传递
access token
的方式。我建议将 refresh token
和 access token
存储在本地存储(或旧浏览器的 cookie)中,并使用 $httpProvider.interceptors.push
为每个 $http
调用添加拦截器。然后拦截器可以将访问令牌添加到标头,如下所示:config.headers['Authorization'] = 'Bearer ' + accessToken;
以角度定义拦截器:
angular.module('app').service('authenticationInterceptor', ['$q', function($q) {
this.request = function(config) {
var accessToken = // ... get the access token from local storage / cookie
config.headers['Authorization'] = 'Bearer ' + accessToken;
return config;
};
}]);
将其添加到
$httpProvider
:
angular.module('app').config(['$httpProvider', ($httpProvider: ng.IHttpProvider) => {
$httpProvider.interceptors.push('authenticationInterceptor');
}]);
我可以对你说的是 Outh2 的“令牌认证”应该可以完成这项工作;当我们谈论安全性时,这是使用 Angular 和 WebAPI 的最简单方法。在这种情况下,Cookie 不是正确的解决方案。
查看
this文章,了解有关如何使用 ASP.NET Web API 2、Owin 和 Identity 实现完整的基于令牌的身份验证的更多详细信息。那篇文章在很多方面确实对我有帮助。最终,当您获得示例解决方案时,您可以返回此处并询问更多“详细信息”。 顺便说一句,我在你的代码中读到了这个“评论”:
//现在棘手的部分是在验证用户身份之后出现的,我应该这样做吗? //只需将用户 ID 存储在我的会话中,就像这样 Session["userid]=id 或 //我应该像我读过的那样将整个用户对象存储在我的cookie中吗
一个我个人认为session是邪恶的。我不是唯一的
。 无论如何,如果你想在 web.api 世界中使用“session”,它不是免费的,你必须激活它。因此,如果出于任何原因您需要使用它,请选中this。 希望有帮助:)
Satellizer 是一个很棒的库,可以添加到您的 Angular 应用程序中
https://github.com/sahat/satellizer <form method="post" ng-submit="login()" name="loginForm">
<div class="form-group has-feedback">
<input class="form-control input-lg" type="text" name="email" ng-model="user.email" placeholder="Email" required autofocus>
<span class="ion-at form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input class="form-control input-lg" type="password" name="password" ng-model="user.password" placeholder="Password" required>
<span class="ion-key form-control-feedback"></span>
</div>
<button type="submit" ng-disabled="loginForm.$invalid" class="btn btn-lg btn-block btn-success">Log in</button>
<br/>
<p class="text-center text-muted">
<small>Don't have an account yet? <a href="/#/signup">Sign up</a></small>
</p>
<div class="signup-or-separator">
<h6 class="text">or</h6>
<hr>
</div>
</form>
JS
angular.module('MyApp')
.controller('LoginCtrl', function($scope, $auth) {
$scope.login = function() {
$auth.login($scope.user)
.then(function() {
toastr.success('You have successfully signed in!');
$location.path('/');
})
.catch(function(error) {
toastr.error(error.data.message, error.status);
});
};
});