我面临的问题是,当我点击MVC应用程序中的“登录”按钮时,API正在生成令牌以及用户信息.但是我无法在视图中显示用户信息.
以下代码位于MVC App的AccountController中
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(Loginviewmodel model) { string token = Token.GetToken(Token.GRANT_TYPE,model.Email,model.Password,Token.CLIENT_ID,Token.CLIENT_SECRET); //token has the appropriate data if I debug it if (!string.IsNullOrEmpty(token)) return RedirectToAction("Index","Home"); return View(model); }
然后在视图中我有
@if (Request.IsAuthenticated) { <p>@User.Identity.GetUserName()</p> //this line is always blank }
API看起来像这样
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin"); if (allowedOrigin == null) allowedOrigin = "*"; context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin",new[] { allowedOrigin }); using (AuthRepository _repo = new AuthRepository()) { ApplicationUser user = await _repo.FindUser(context.UserName,context.Password); if (user == null) { context.SetError("invalid_grant","The user name or password is incorrect."); return; } } var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name,context.UserName)); identity.AddClaim(new Claim(ClaimTypes.Role,"user")); identity.AddClaim(new Claim("sub",context.UserName)); var props = new AuthenticationProperties(new Dictionary<string,string> { { "as:client_id",(context.ClientId == null) ? string.Empty : context.ClientId },{ "userName",context.UserName },{ "email",}); var ticket = new AuthenticationTicket(identity,props); context.Validated(ticket); }
有人能告诉我为什么请求没有被认证?我错过了什么
解决方法
惯例是使用GrantResourceOwnerCredentials作为端点(/ api / token),它接收凭证并返回访问令牌.
按照惯例,此端点替换Login(Loginviewmodel)方法.显然你不应该使用Login()方法,但我怀疑你是.
>如果您使用的是Login方法,它只会返回原始的,未更改的View Cre Model with Credentials.您的Loginviewmodel类可能包含令牌属性,但您没有填充它.因此,登录方法会对您的用户进行身份验证,但不会对其进行授权,因为用户永远不会获取其访问令牌.
>您的GrantResourceOwnerCredentials方法确实返回令牌并填充声明.但是,您是否有任何客户端逻辑来存储访问令牌并在每个请求中发送它?
>除非您的令牌采用JWT(Json Web令牌)之类的格式,否则我怀疑取消加密令牌以访问声明(例如userName / email)将是一项重大挑战.这意味着,除非是JWT,否则客户端从访问令牌中提取声明并不容易.
第二部分:有人可以告诉我为什么请求没有被认证?
您正在通过身份验证.但这不是表单身份验证.没有Cookie.当API返回访问令牌时,Razor Calls to Identity将无法工作.
在典型的Forms Auth模型中:
凭证被发送和验证(经过身份验证).如果验证成功,则用户被授权(给定访问权限),其客户端cookie具有加密的访问信息和声明. OWIN Middle-ware在每个请求上读取Cookie并填充httpContext(Identity是httpContext对象上的属性.)
访问令牌工作流程:
非常相似,除了,因为没有Cookie,并且API和客户端View之间没有连接,而不是View Models中返回的数据.每次OWIN中间件读取访问令牌时,除了在服务器端(Web API)之外,不会填充httpContext.
所以,剃刀召唤
@User.Identity.GetUserName()
会出现空洞.
如果您需要来自服务器的用户信息,您应该在客户端上缓存用户名(以及您需要的任何其他信息).
>会话存储
>本地存储
> JavaScript单例类(如Angular服务)
>存储用户输入凭据时获得的用户名(如果身份验证失败,请清除它)
>有一个专用的终点(API方法)来返回您想要的用户信息
>返回JWT的索赔.
如果您更改令牌类型(在Global.asax或Startup.cs中 – 取决于您配置的方式)以使用Jason Web Tokens,客户端将能够取消您的令牌编码并将声明作为JSON数组读取.
>最后一个选项:您可以同时使用访问令牌和Cookie.您可以返回访问令牌并创建cookie.在配置Web API时,为Web API禁止cookie auth.>最后的想法:访问令牌用于额外的安全级别(cookie更容易受到攻击).但是您使用Access Tokens的目的是什么?如果您正在创建与AngularJS类似的SPA(单页应用程序),则此类安全性更为重要.否则,Cookie Auth是一个更简单的工作流程,除非您觉得需要额外的安全性,否则Cookie更可取.