重定向至"使用 Ajax 授权控制器"诊断树



我有一个问题,需要澄清一下。我有一个帐户控制器,其中包含处理登录的登录操作,如果成功,它会将用户重定向到我希望用 jwt 保护它的主页。所以我的问题是这样的,我知道我正确地重定向到我的主页/索引,但我缺少一些东西来验证提供的令牌。1. 我需要在HomeController 类的顶部添加什么属性标签?2. 我怎样才能通过"@Url.Action("索引","主页"("?

编辑:成功登录后,它说我已经成功登录,但由于我需要令牌在标头中,当我尝试使用 @Url.Action(( 重定向时,它会发送错误请求,因为我不确定如何填充标头。

这是启动.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Chat.Controllers;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
namespace Chat
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "localhost",
ValidAudience = "localhost",
IssuerSigningKey = AccountController.SIGNING_KEY
};
});
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Account}/{action=Index}/{id?}");
});
}
}
}

以下是具有登录操作的帐户控制器:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Chat.Models;
using Chat.DatabaseAccessObject;
using Chat.Identity;
using Chat.DatabaseAccessObject.CommandObjects;
using System.Linq.Expressions;
using System.Net.Mime;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication;
using Microsoft.IdentityModel.Tokens;
namespace Chat.Controllers
{
public class AccountController : Controller
{
private const string SECRET_KEY = "CHATSECRETKEY";
public static SymmetricSecurityKey SIGNING_KEY = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SECRET_KEY));
private ServerToStorageFacade serverToStorageFacade = new ServerToStorageFacade();
private AuthenticateUser authenticateUser = new AuthenticateUser();
public IActionResult Index()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Login([FromBody]LoginModel loginModel)
{
if (ModelState.IsValid)
{
var mapLoginModelToUser = new MapLoginModelToUser();
var user = await mapLoginModelToUser.MapObject(loginModel);
// If login user with those credentials does not exist
if(user == null)
{
return BadRequest();
}
else
{
var result = await this.authenticateUser.Authenticate(user);
if(result.Result == Chat.Enums.AuthenticateResult.Success)
{
// SUCCESSFUL LOGIN
// Creating and storing cookies
var token = Json(new
{
data = this.GenerateToken(user.Email, user.PantherID),
redirectUrl = Url.Action("Index","Home"),
success = true
});
return Ok(token);
}
else
{
// Unsuccessful login
return Unauthorized();
}
}
}
return BadRequest();
}
private string GenerateToken(string email, string pantherId)
{
var claimsData = new[] { new Claim(ClaimTypes.Email, email), new Claim(ClaimTypes.Actor, pantherId) };
var signInCredentials = new SigningCredentials(SIGNING_KEY, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "localhost",
audience: "localhost",
expires: DateTime.Now.AddDays(7),
claims: claimsData,
signingCredentials: signInCredentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public async Task<IActionResult> Error() => View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}

以下是位于"/Views/Account/Index.cshtml"中的 Index.cshtml:

@{
Layout = null;
ViewData["Title"] = "Login";
}
@model Chat.Models.LoginModel
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="/css/signin.css" rel="stylesheet">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/Login.js"></script>
</head>
<body class="text-center">
<form id="formSubmit" method="post" class="form-signin">
<img class="mb-4" src="~/images/Chat-Curved.png" alt="" width="150" height="150">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
@Html.TextBoxFor(m => m.inputEmail, new { @class = "form-control", @type="email", @placeholder = "Email address", @required = "required", @autofocus = "" })
<label for="inputPassword" class="sr-only">Password</label>
@Html.PasswordFor(m => m.inputPassword, new { @class = "form-control", @type="password", @placeholder = "Password", @required = "required"})
<div class="checkbox mb-3">
<label>
@Html.CheckBoxFor(m => m.rememberMe)  Remeber me
</label>
</div>
<button id="btnLogin" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">&copy; 2017-2018</p>
</form>
</body>
</html>

下面是具有索引操作的主控制器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Chat.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
}

这是 Index.cshtml 引用的登录名.js:

$(document).ready(function () {
$("#formSubmit").submit(function (event) {
event.preventDefault();
var email = $("#inputEmail").val();
var password = $("#inputPassword").val();
var remember = $("#rememberMe").val();
var loginModel = {
inputEmail: email,
inputPassword: password,
rememberMe: remember
};
$.ajax({
type: 'POST',
url: 'Account/Login',
data: JSON.stringify(loginModel),
contentType: 'application/json; charset=utf-8;',
success: function (response) {
var token = response.value.data;
localStorage.setItem("token", token);
window.location.href = response.value.redirectUrl;
}
});
});
});

如果要授权控制器,则必须使用中间件(ActionFilterAttribute(,它将检测用户的http请求并通过解码用户的令牌来验证它们。 您可以过滤所有HTTP方法(GET,POST,PUT,DELETE...等(,并且可以针对特定的 http 方法实现您自己的授权逻辑。

授权必需属性.cs

注意:这里所有代码都与您的问题无关。 但希望你能理解。

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class AuthorizationRequiredAttribute : ActionFilterAttribute
{
private readonly IAccessTokenServices _accessTokenServices;
private readonly IPermissionServices _permissionServices;
private readonly IAuditLogServices _auditLogServices;
private IConfiguration _config;
public AuthorizationRequiredAttribute(IAccessTokenServices accessTokenServices, IPermissionServices permissionServices,
IAuditLogServices auditLogServices,IConfiguration config)
{
_accessTokenServices = accessTokenServices;
_config = config;
_permissionServices = permissionServices;
_auditLogServices = auditLogServices;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
try
{
if (context.HttpContext.Request.Headers.ContainsKey(Constants.HttpHeaders.Token))
{
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadToken(context.HttpContext.Request.Headers[Constants.HttpHeaders.Token])
as JwtSecurityToken;
var expireDate = Convert.ToDateTime(token.Claims.First(claim => claim.Type == Constants.JwtClaims.ExpiresOn).Value);
if (context.HttpContext.Request.Method == WebRequestMethods.Http.Get)
{
if (expireDate < DateTime.Now)
{
context.Result = new UnauthorizedResult();
}
}
else
{
var accessToken = _accessTokenServices
.Details(x => x.Token == context.HttpContext.Request.Headers[Constants.HttpHeaders.Token]);
if (accessToken != null)
{
if (accessToken.ExpiresOn < DateTime.Now)
{
_accessTokenServices.Delete(accessToken);
context.Result = new UnauthorizedResult();
}
else
{
var userId = Convert.ToInt32(token.Claims.First(claim => claim.Type == Constants.JwtClaims.UserId).Value);
var userTypeId = Convert.ToInt32(token.Claims.First(claim => claim.Type == Constants.JwtClaims.UserTypeId).Value);
if (accessToken == null)
{
context.Result = new UnauthorizedResult();
}
else if (!_permissionServices.IsPermissionExist(context.HttpContext.Request.Path.ToString(), userTypeId))
{
context.Result = new StatusCodeResult((int)HttpStatusCode.NotAcceptable);
}
else
{
_auditLogServices.Save(context.HttpContext.Request.Path.ToString(), userId);
accessToken.ExpiresOn = DateTime.Now.AddMinutes(Convert.ToInt16(_config["Jwt:ExpiresOn"]));
_accessTokenServices.UpdateExpireTime(accessToken);
}
}
}
else
{
context.Result = new UnauthorizedResult();
}
}
}
else
{
context.Result = new NotFoundResult();
}
}
catch (Exception ex)
{
context.Result = new BadRequestResult();
}
base.OnActionExecuting(context);
}
}

}

首页控制器.cs

现在,您可以将 AuthorizationRequiredAttribute 用作 api/controller 筛选器服务。 我已经修改了您的控制器并看到了消息方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Chat.Controllers
{
[Route("api/home")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpGet("message"), ServiceFilter(typeof(AuthorizationRequiredAttribute))]
public IActionResult Message()
{
return Ok("Hello World!");
}
}
}

最新更新