我有一个问题,需要澄清。我有一个AccountLogin,它具有处理登录的Login操作,如果成功,它将把用户重定向到我希望用jwt保护它的主页。所以我的问题是,我知道我可以正确重定向到我的家庭/索引,但是我缺少一些东西来对提供的令牌进行身份验证。 1.我需要在HomeController类的顶部添加什么属性标签? 2.如何传递'@ Url.Action(“ Index”,“ Home”)'?
编辑:成功登录后,它表示我已经成功登录,但是由于我要求令牌位于标头中,因此当我尝试使用@ Url.Action()进行重定向时,它发送错误请求,原因是我不确定如何用此填充标头。
这是Startup.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?}");
});
}
}
}
这是具有登录操作的AccountController:
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">© 2017-2018</p>
</form>
</body>
</html>
这里是带有索引操作的HomeController:
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引用的Login.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;
}
});
});
});
答案 0 :(得分:0)
如果要授权控制器,则必须使用中间件( ActionFilterAttribute ),该中间件将检测用户的http请求并通过解码用户的令牌来验证它们。您可以过滤所有http方法(GET,POST,PUT,DELETE等),并可以为特定的http方法实现自己的授权逻辑。
AuthorizationRequiredAttribute.cs
N.B:此处所有代码均与您的问题无关。但希望您能理解。
[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);
}
}
}
HomeController.cs
现在,您可以将AuthorizationRequiredAttribute用作api /控制器过滤器服务。我已经修改了您的控制器并查看Message方法
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!");
}
}
}