Commit 29b7aa9a authored by 梁桐铭's avatar 梁桐铭 🏅

完成119的内容。准备升级到3.1

parent 0eb90bce
......@@ -5,6 +5,11 @@ VisualStudioVersion = 16.0.28729.10
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StudentManagement", "StudentManagement\StudentManagement.csproj", "{C919EF40-4E54-40D9-980F-E06B14BA4D2E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D130613B-57A3-4668-AC87-DA044F217B52}"
ProjectSection(SolutionItems) = preProject
..\README.md = ..\README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using StudentManagement.Models;
using StudentManagement.Security.CustomTokenProvider;
using StudentManagement.ViewModels;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace StudentManagement.Controllers
{
......@@ -18,15 +21,16 @@ namespace StudentManagement.Controllers
private readonly HostingEnvironment hostingEnvironment;
private readonly ILogger logger;
private readonly IDataProtector dataProtector;
//使用构造函数注入的方式注入IStudentRepository
public HomeController(IStudentRepository studentRepository, HostingEnvironment hostingEnvironment,
ILogger<HomeController> logger)
ILogger<HomeController> logger,DataProtectionPurposeStrings dataProtectionPurposeStrings,IDataProtectionProvider dataProtectionProvider)
{
_studentRepository = studentRepository;
this.hostingEnvironment = hostingEnvironment;
this.logger = logger;
dataProtector = dataProtectionProvider.CreateProtector(dataProtectionPurposeStrings.StudentIdRouteValue);
}
......@@ -34,7 +38,12 @@ namespace StudentManagement.Controllers
public IActionResult Index()
{
IEnumerable<Student> students = _studentRepository.GetAllStudents();
IEnumerable<Student> students = _studentRepository.GetAllStudents().
Select(s=>{
//加密ID值并存储在EncryptedId属性中
s.EncryptedId = dataProtector.Protect(s.Id.ToString());
return s;
});
return View(students);
......@@ -43,30 +52,33 @@ namespace StudentManagement.Controllers
public IActionResult Details(int id)
// Details视图接收加密后的StudentID
public IActionResult Details(string id)
{
logger.LogTrace("Trace(跟踪) Log");
logger.LogDebug("Debug(调试) Log");
logger.LogInformation("信息(Information) Log");
logger.LogWarning("警告(Warning) Log");
logger.LogError("错误(Error) Log");
logger.LogCritical("严重(Critical) Log");
//logger.LogTrace("Trace(跟踪) Log");
//logger.LogDebug("Debug(调试) Log");
//logger.LogInformation("信息(Information) Log");
//logger.LogWarning("警告(Warning) Log");
//logger.LogError("错误(Error) Log");
//logger.LogCritical("严重(Critical) Log");
// throw new Exception("此异常发生在Details视图中");
//使用 Unprotect()方法来解析学生id
var decryptedId = dataProtector.Unprotect(id);
// throw new Exception("此异常发生在Details视图中");
var decryptedStudentId= Convert.ToInt32(decryptedId);
Student student = _studentRepository.GetStudent(id);
Student student = _studentRepository.GetStudent(decryptedStudentId);
if (student==null)
if (student == null)
{
Response.StatusCode = 404;
return View("StudentNotFound",id);
ViewBag.ErrorMessage = $"学生Id={id}的信息不存在,请重试。";
return View("NotFound");
}
//实例化HomeDetailsViewModel并存储Student详细信息和PageTitle
......@@ -75,6 +87,7 @@ namespace StudentManagement.Controllers
Student = student,
PageTitle = "学生详细信息"
};
//将ViewModel对象传递给View()方法
return View(homeDetailsViewModel);
}
......
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
......@@ -27,7 +28,9 @@ namespace StudentManagement.Models
public string PhotoPath { get; set; }
[NotMapped]
public string EncryptedId { get; set; }
......
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentManagement.Security.CustomTokenProvider
{
/// <summary>
/// 自定义邮件验证令牌提供程序
/// </summary>
/// <typeparam name="TUser"></typeparam>
public class CustomEmailConfirmationTokenProvider<TUser> : DataProtectorTokenProvider<TUser> where TUser : class
{
public CustomEmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
IOptions<CustomEmailConfirmationTokenProviderOptions> options) : base(dataProtectionProvider, options)
{
}
}
}
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentManagement.Security.CustomTokenProvider
{
/// <summary>
/// 自定义的令牌配置类
/// </summary>
public class CustomEmailConfirmationTokenProviderOptions:DataProtectionTokenProviderOptions
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentManagement.Security.CustomTokenProvider
{
public class DataProtectionPurposeStrings
{
public readonly string StudentIdRouteValue = "StudentIdRouteValue";
}
}
......@@ -11,6 +11,7 @@ using StudentManagement.Data;
using StudentManagement.Middlewares;
using StudentManagement.Models;
using StudentManagement.Security;
using StudentManagement.Security.CustomTokenProvider;
using System;
namespace StudentManagement
......@@ -45,19 +46,32 @@ namespace StudentManagement
options.Password.RequireUppercase = false;
options.SignIn.RequireConfirmedEmail = true;
});
//services.Configure<DataProtectionTokenProviderOptions>(
// opt=>opt.TokenLifespan=TimeSpan.FromHours(10))
// ;
//通过自定义的CustomEmailConfirmation名称来覆盖旧有token名称,
//是它与AddTokenProvider<CustomEmailConfirmationTokenProvider<ApplicationUser>>("ltmEmailConfirmation")
//关联在一起
options.Tokens.EmailConfirmationTokenProvider = "ltmEmailConfirmation";
//指 在帐户被锁定之前允许的失败登录的次数。默认值为 5。
options.Lockout.MaxFailedAccessAttempts = 5;
//默认锁定时间为 15 分钟。
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
});
/// 修改所有令牌类型的有效时间为10个小时
services.Configure<DataProtectionTokenProviderOptions>(
opt =>
{
opt.TokenLifespan = TimeSpan.FromHours(10);
}
);
// 仅更改电子邮件验证令牌类型的有效时间为10秒
services.Configure<CustomEmailConfirmationTokenProviderOptions>(opt =>
{
opt.TokenLifespan = TimeSpan.FromHours(10);
}
);
services.ConfigureApplicationCookie(options =>
{
......@@ -77,7 +91,13 @@ namespace StudentManagement
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<CustomIdentityErrorDescriber>()
.AddEntityFrameworkStores<AppDbContext>().AddDefaultTokenProviders();
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders()
.AddTokenProvider<CustomEmailConfirmationTokenProvider<ApplicationUser>>("ltmEmailConfirmation")
;
// 策略结合声明授权
services.AddAuthorization(options =>
......@@ -122,6 +142,10 @@ namespace StudentManagement
services.AddSingleton<IAuthorizationHandler, CanEditOnlyOtherAdminRolesAndClaimsHandler>();
services.AddSingleton<IAuthorizationHandler, SuperAdminHandler>();
services.AddSingleton<DataProtectionPurposeStrings>();
}
......
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace StudentManagement.ViewModels
{
public class AddPasswordViewModel
{
[Required]
[DataType(DataType.Password)]
[Display(Name = "新密码:")]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
[Display(Name = "确认新密码")]
[Compare("NewPassword", ErrorMessage =
"新密码和确认密码不匹配。")]
public string ConfirmPassword { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace StudentManagement.ViewModels
{
public class ChangePasswordViewModel
{
[Required]
[DataType(DataType.Password)]
[Display(Name = "当前密码:")]
public string CurrentPassword { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "新密码:")]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
[Display(Name = "确认新密码")]
[Compare("NewPassword", ErrorMessage =
"新密码和确认密码不匹配。")]
public string ConfirmPassword { get; set; }
}
}
@{
ViewBag.Title = "账号锁定";
}
<h3 class="text-danger">
您的帐户已锁定,请稍后再试一次,否则您的账户还可能被锁定。
<a asp-action="ForgotPassword" asp-controller="Account">
点击这里重置密码
</a>
</h3>
\ No newline at end of file

@{
ViewBag.Title = "添加密码";
}
@model AddPasswordViewModel
<h2>添加密码</h2>
<hr />
<p class="text-info">
您当前使用的外部帐户登录,还没有设置本地用户名和密码。
如果您想使用本地帐户登录,只需设置一个新密码。
可以使用您的电子邮件作为用户名。
</p>
<div class="row">
<div class="col-md-12">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="NewPassword"></label>
<input asp-for="NewPassword" class="form-control" />
<span asp-validation-for="NewPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword"></label>
<input asp-for="ConfirmPassword" class="form-control" />
<span asp-validation-for="ConfirmPassword" class="text-danger"> </span>
</div>
<button type="submit" class="btn btn-primary" style="width:auto">
设置密码
</button>
</form>
</div>
</div>
\ No newline at end of file
@{
ViewBag.Title = "密码设置成功";
}
<h1 class="text-info">密码设置成功</h1>
<h4 class="text-secondary">
您已经成功地设置了本地密码。现在您可以随意选择
您的本地用户帐户或外部帐户登录到系统中。
</h4>
<a asp-controller="home"
asp-action="index"
class="btn btn-outline-success"
style="width:auto">
点击此处返回首页
</a>
\ No newline at end of file
@{
ViewBag.Title = "修改密码";
}
@model ChangePasswordViewModel
<h2>修改密码</h2>
<hr />
<div class="row">
<div class="col-md-12">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="CurrentPassword"></label>
<input asp-for="CurrentPassword" class="form-control" />
<span asp-validation-for="CurrentPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NewPassword"></label>
<input asp-for="NewPassword" class="form-control" />
<span asp-validation-for="NewPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword"></label>
<input asp-for="ConfirmPassword" class="form-control" />
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">更新</button>
</form>
</div>
</div>
\ No newline at end of file
@{
ViewBag.Title = "修改密码结果通知";
}
<h1 class="text-info">修改密码结果通知</h1>
<h4 class="text-secondary">
您的密码已经修改成功。
</h4>
<a asp-controller="home" asp-action="index" class="btn btn-outline-success" style="width:auto"> 点击此处返回首页</a>
\ No newline at end of file
......@@ -22,7 +22,7 @@
<img class="card-img-top imagesThumbnail" src="@photoPath" asp-append-version="true" />
<div class="card-footer text-center">
<a asp-controller="home" asp-action="details" asp-route-id="@student.Id" class="btn btn-primary m-1">查看</a>
<a asp-controller="home" asp-action="details" asp-route-id="@student.EncryptedId" class="btn btn-primary m-1">查看</a>
<a asp-controller="home" asp-action="edit" asp-route-id="@student.Id" class="btn btn-primary m-1">编辑</a>
......
@model int
@{
ViewBag.Title = "404找不到内容";
}
<div class="alert alert-danger mt-1 mb-1" >
<h4>404 Not Found 错误</h4>
<hr />
<h5>查询不到学生ID为@(Model)的信息</h5>
</div>
<a asp-controller="home" asp-action="index" class="btn btn-outline-success"
style="width:auto"
>点击此处查看学生列表</a>
\ No newline at end of file
......@@ -51,26 +51,33 @@
<a class="nav-link" asp-controller="home" asp-action="Create">添加学生</a>
</li>
@if (SignInManager.IsSignedIn(User) && User.IsInRole("Admin"))
@if (SignInManager.IsSignedIn(User))
{
<li class="nav-item dropdown">
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">管理</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">管理</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
@if (User.IsInRole("Admin"))
{<a class="dropdown-item" asp-controller="Admin" asp-action="ListRoles">角色列表</a>
<a class="dropdown-item" asp-controller="Admin" asp-action="ListUsers">用户列表</a>
<a class="dropdown-item" asp-controller="Admin" asp-action="ListRoles">角色列表</a>
<a class="dropdown-item" asp-controller="Admin" asp-action="ListUsers">用户列表</a>
</div>
}
<a class="dropdown-item" asp-controller="Account" asp-action="ChangePassword">密码管理</a>
</li>
</div>
</li>
}
</ul>
<ul class="navbar-nav ml-auto">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment