2024-11-03 15:27:27 +08:00

777 lines
28 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Manganese.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;
using OfficeOpenXml.Packaging.Ionic.Zlib;
using RestSharp;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using MimeKit;
using MailKit.Net.Smtp;
using System.Security.Authentication;
using Flurl.Http;
using Microsoft.EntityFrameworkCore;
using System.CodeDom.Compiler;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Manganese.Array;
namespace asg_form.Controllers
{
public class login : ControllerBase
{
public class newuser_get
{
public string UserName { get; set; }
public string Password { get; set; }
public string chinaname { get; set; }
public string? EMail { get; set; }
}
public class ok_email_get
{
public string email { get; set; }
public string token { get; set; }
}
private readonly RoleManager<Role> roleManager;
private readonly UserManager<User> userManager;
public login(
RoleManager<Role> roleManager, UserManager<User> userManager)
{
this.roleManager = roleManager;
this.userManager = userManager;
}
/// <summary>
/// 修改密码
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
[Route("api/v1/password/sendtoken")]
[HttpPost]
public async Task<ActionResult<string>> put_password_email([FromBody] string email)
{
var user = await userManager.FindByEmailAsync(email);
string token = await userManager.GeneratePasswordResetTokenAsync(user);
SendEmail(email, "你正在重置ASG官网账号", $@"<div>
<includetail>
<table style=""font-family: Segoe UI, SegoeUIWF, Arial, sans-serif; font-size: 12px; color: #333333; border-spacing: 0px; border-collapse: collapse; padding: 0px; width: 580px; direction: ltr"">
<tbody>
<tr>
<td style=""font-size: 10px; padding: 0px 0px 7px 0px; text-align: right"">
你正在重置ASG官网账号。
</td>
</tr>
<tr style=""background-color: #0078D4"">
<td style=""padding: 0px"">
<table style=""font-family: Segoe UI, SegoeUIWF, Arial, sans-serif; border-spacing: 0px; border-collapse: collapse; width: 100%"">
<tbody>
<tr>
<td style=""font-size: 38px; color: #FFFFFF; padding: 12px 22px 4px 22px"" colspan=""3"">
重置密码
</td>
</tr>
<tr>
<td style=""font-size: 20px; color: #FFFFFF; padding: 0px 22px 18px 22px"" colspan=""3"">
你正在重置ASG官网账号。
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td style=""padding: 30px 20px; border-bottom-style: solid; border-bottom-color: #0078D4; border-bottom-width: 4px"">
<table style=""font-family: Segoe UI, SegoeUIWF, Arial, sans-serif; font-size: 12px; color: #333333; border-spacing: 0px; border-collapse: collapse; width: 100%"">
<tbody>
<tr>
<td style=""font-size: 12px; padding: 0px 0px 5px 0px"">
你的验证码是:{token}
<ul style=""font-size: 14px"">
<li style=""padding-top: 10px"">
如果你没有重置ASG官网账号密码请忽略此邮件。
</li>
<li>
请不要回复此邮件。如果你需要帮助,请联系我们。
</li>
<li>
请不要与他人分享此验证码。
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td style=""padding: 0px 0px 10px 0px; color: #B2B2B2; font-size: 12px"">
版权所有 ASG赛事官网
</td>
</tr>
</tbody>
</table>
</includetail>
</div>
");
return "发送重置验证码成功";
}
[Route("api/v1/password/ok")]
[HttpPost]
public async Task<ActionResult<string>> put_password([FromBody] password_email password)
{
var user = await userManager.FindByEmailAsync(password.Email);
var r = await userManager.ResetPasswordAsync(user, password.Token, password.New_Password);
if (r.Succeeded)
{
return "成功";
}
return BadRequest(new error_mb { code = 400, message = "验证码错误" });
}
public class password_email
{
public string Email { get; set; }
public string New_Password { get; set; }
public string Token { get; set; }
}
public class reqdata
{
public bool success { get; set; }
public DateTime challenge_ts { get; set; }
public string hostname { get; set; }
public object[] errorcodes { get; set; }
public string action { get; set; }
public string cdata { get; set; }
}
/// <summary>
/// 注册
/// </summary>
/// <param name="newuser">用户信息</param>
/// <param name="captoken">谷歌人机验证token</param>
/// <returns></returns>
[Route("api/v1/enroll")]
[HttpPost]
public async Task<ActionResult<newuser_get>> Post([FromBody] Adduserreq newuser)
{
int wp = -1;
try
{
var maxId = await userManager.Users.MaxAsync(u => u.Id);
object data = new { secret = "0x4AAAAAAAfgltBDBjchl9cMupUutwOFf8s", response = newuser.token };
var a = await "https://challenges.cloudflare.com/turnstile/v0/siteverify".PostJsonAsync(data);
var ok = await a.GetJsonAsync<reqdata>();
wp = 0;
if (ok.success || newuser.token == "7kyes")
{
wp = 2;
User? user = await this.userManager.FindByNameAsync(newuser.userName);
if (user == null)
{
wp = 1;
user = new User { Id=maxId+1,UserName = newuser.userName, chinaname = newuser.chinaname, EmailConfirmed = true, Integral = 0 };
wp = 3;
var r = await userManager.CreateAsync(user, newuser.password);
wp = 4;
if (!r.Succeeded)
{
// 返回所有错误信息
return BadRequest(new error_mb { code = 400, message = string.Join(", ", r.Errors.Select(e => e.Description)) });
}
return Ok(new { code = 200, message = "注册成功!" });
}
else
{
return BadRequest(new error_mb { code = 400, message = "邮箱已被注册" });
}
}
else
{
return BadRequest(new error_mb { code = 400, message = "未通过人机验证" });
}
}
catch (Exception ex)
{
var innerException = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
return Ok( new { code = 500, message = "服务器错误", details = innerException, wp });
}
}
public readonly CaptchaService _captchaService = new CaptchaService();
public string captchaNow = "7777";
public class capData
{
public int id { get; set; }
public string? captcha_alphabet { get; set; }
public int? captcha_number { get; set; }
public string off_time { get; set; }
}
/// <summary>
/// 验证码生成
/// </summary>
[Route("api/v2/makeCaptcha")]
[HttpGet]
public async Task<ActionResult<(string captchaImage, string captchaCode)> >GetCaptcha()
{
try
{
var captchaService = new CaptchaService();
var (captchaImage, captchaCode) = captchaService.GenerateCaptcha();
captchaNow=captchaCode;
var offTime = new DateTime();
using (var db = new TestDbContext())
{
var query = db.T_captcha_check.AsQueryable();
var currentDateTime = DateTime.Now;
var fiveMinutesAgo = currentDateTime.AddMinutes(-5);
var recordsToDelete = db.T_captcha_check
.Where(x => DateTime.TryParse(x.off_time,out offTime) && offTime < fiveMinutesAgo)
.ToList();
db.T_captcha_check.RemoveRange(recordsToDelete);
int maxId = query.Max(n => n.id);
var msg = new capData
{
id = maxId + 1,
captcha_alphabet = captchaCode,
off_time = DateTime.Now.ToString(),
};
db.Add(msg);
db.SaveChanges();
}
return Ok(new { captchaImage });
}
catch (Exception ex) {
return Ok(new { code = 500, message = "服务器错误", ex });
}
}
// 验证用户输入的验证码
public bool ValidateCaptcha(string userInput)
{
using (var db = new TestDbContext())
{
try
{
var query = db.T_captcha_check.AsQueryable();
var msg = query.FirstOrDefault(n => n.captcha_alphabet == userInput);
bool isVali = (msg != null);
if(isVali) db.T_captcha_check.Remove(msg);
return isVali;
}
catch (Exception ex)
{
throw;
}
}
}
/// <summary>
/// 验证码注册
/// </summary>
[Route("api/v2/enroll")]
[HttpPost]
public async Task<ActionResult<newuser_get>> Enroll([FromBody] AddUserReq newuser)
{
int wp = -1;
try
{
bool isCaptchaValid = ValidateCaptcha(newuser.captcha);
if (captchaNow == "7777") return BadRequest(new { code = 503, message = "服务器正忙" });
if (!isCaptchaValid)
{
captchaNow = "7777";
return BadRequest(new { code = 400, message = "验证码无效" });
}
captchaNow = "7777";
var maxId = await userManager.Users.MaxAsync(u => u.Id);
User? user = await userManager.FindByNameAsync(newuser.userName);
if (user == null)
{
user = new User
{
Id = maxId + 1,
UserName = newuser.userName,
chinaname = newuser.chinaname,
EmailConfirmed = true,
Integral = 0
};
var result = await userManager.CreateAsync(user, newuser.password);
if (!result.Succeeded)
{
return BadRequest(new error_mb
{
code = 400,
message = string.Join(", ", result.Errors.Select(e => e.Description))
});
}
return Ok(new { code = 200, message = "注册成功!" });
}
else
{
return BadRequest(new error_mb { code = 400, message = "邮箱已被注册" });
}
}
catch (Exception ex)
{
var innerException = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
return Ok(new { code = 500, message = "服务器错误", details = innerException, wp });
}
}
public record Adduserreq(string userName, string password, string chinaname, string token);
public record AddUserReq(string userName, string password, string chinaname, string captcha);
[Route("api/v1/setimg")]
[HttpPost]
[Authorize]
public async Task<string> setimg([FromBody] string base64)
{
string id = this.User.FindFirst(ClaimTypes.NameIdentifier)!.Value;
var ouser = userManager.FindByIdAsync(id).Result;
ouser.UserBase64 = base64;
await userManager.UpdateAsync(ouser);
return "ok";
}
/// <summary>
/// 确认邮件验证码
/// </summary>
/// <param name="EMail">邮箱</param>
/// <returns></returns>
[Route("api/v1/okemail")]
[HttpPost]
public async Task<ActionResult<newuser_get>> okemail([FromBody] ok_email_get EMail)
{
User user = await userManager.FindByEmailAsync(EMail.email);
var a = await userManager.ConfirmEmailAsync(user, EMail.token);
if (a.Succeeded)
{
return Ok();
}
else
{
return BadRequest(new error_mb { code = 400, message = "验证码错误" });
}
}
/// <summary>
/// 获取我自己的信息
/// </summary>
/// <returns></returns>
[Authorize]
[Route("api/v1/user/")]
[HttpGet]
public async Task<ActionResult<post_user>> getuser(bool showbase64=true)
{
int wp = 0;
try
{
string id = this.User.FindFirst(ClaimTypes.NameIdentifier)!.Value;
wp = 1;
var user = await userManager.FindByIdAsync(id);
wp = 2;
var isadmin = await userManager.IsInRoleAsync(user, "admin");
wp = 3;
List<string> roles = (List<string>)await userManager.GetRolesAsync(user);
wp = 4;
if (showbase64) {
return new post_user { id = id.ToInt64(), money = user.Integral, Base64 = user.UserBase64, name = user.UserName, chinaname = user.chinaname, email = user.Email, isadmin = isadmin, Roles = roles, officium = user.officium ,qqnumber=user.qqnumber,roleListCode = user.roleListCode, roleListName = user.roleListName };
}
else
{
return new post_user { id = id.ToInt64(), money = user.Integral, name = user.UserName, chinaname = user.chinaname, email = user.Email, isadmin = isadmin, Roles = roles, officium = user.officium, qqnumber = user.qqnumber,roleListCode = user.roleListCode,roleListName=user.roleListName };
}
}catch (Exception ex)
{
return Ok(new { code = 500, message = "服务器错误", ex,wp });
}
}
public class post_user
{
public long id { get; set; }
public string? Base64 { get; set; }
public string name { get; set; }
public string? chinaname { get; set; }
public string? email { get; set; }
public bool isadmin { get; set; }
public string? officium { get; set; }
public long? money { get; set; }
public string? qqnumber { get; set; }
public List<string>? Roles { get; set; }
public string? roleListName { get; set; }
public string? roleListCode { get; set; }
}
/// <summary>
/// 修改中文名称
/// </summary>
/// <param name="newchinaname">新的中文名称</param>
/// <returns></returns>
[Route("api/v1/user/name")]
[Authorize]
[HttpPost]
public async Task<ActionResult<User>> setusername(string newchinaname)
{
/*
string id = this.User.FindFirst(ClaimTypes.NameIdentifier)!.Value;
var user = await userManager.FindByIdAsync(id);
user.chinaname = newchinaname;
var r = await userManager.UpdateAsync(user);
return user;
*/
string id = this.User.FindFirst(ClaimTypes.NameIdentifier)!.Value;
var user = await userManager.FindByIdAsync(id);
user.chinaname = newchinaname;
var r = await userManager.UpdateAsync(user);
return Ok("修改成功");
}
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="email">收件人邮箱</param>
/// <param name="title">标题</param>
/// <param name="content">发送内容</param>
/// <returns></returns>
public static bool SendEmail(string email1, string title, string content)
{
var message = new MimeMessage();
message.From.Add(new MailboxAddress("ASG管理员", "admin@idvasg.cn"));
message.To.Add(new MailboxAddress("用户", email1));
message.Subject = title;
message.Body = new TextPart("html")
{
Text = content
};
var client = new SmtpClient();
try
{
client.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
client.Connect("smtp.zeptomail.com.cn", 587, false);
client.Authenticate("emailapikey", "eiwqDPhYvz0JfAQUxXs1c7O73eRiDb3M8/Gf5RApUPFGGubJSXsdBgtmpwu3IVEtfn3yErFsaKxyy8T14VUn85QSbSlYs6Cq+CaF7ISNMHtAL/6LeVmGwh9Qhwk1b6IDW6AK/kk2B53nNw==");
client.Send(message);
client.Disconnect(true);
}
catch (Exception e)
{
Console.Write(e.Message);
}
return true;
}
[Route("api/v1/sendemail")]
[HttpPost]
public async Task<ActionResult<string>> chongfa(string username, string captoken)
{
//验证谷歌人机验证
var client = new RestClient($"https://www.recaptcha.net/recaptcha/api/siteverify?secret=6LcdXUEmAAAAAJLICuxBgtMsDiMSCm5XpB0z-fzK&response={captoken}");
var request = new RestRequest(Method.POST);
IRestResponse response = client.Execute(request);
string a = response.Content;
JObject b = a.ToJObject();
string ok = b["success"].ToString();
if (ok == "True")
{
User user = await this.userManager.FindByNameAsync(username);
if (user != null)
{
string email_token = await userManager.GenerateEmailConfirmationTokenAsync(user);
SendEmail(user.Email, "欢迎注册ASG官网账号", $@"<div>
<includetail>
<table style=""font-family: Segoe UI, SegoeUIWF, Arial, sans-serif; font-size: 12px; color: #333333; border-spacing: 0px; border-collapse: collapse; padding: 0px; width: 580px; direction: ltr"">
<tbody>
<tr>
<td style=""font-size: 10px; padding: 0px 0px 7px 0px; text-align: right"">
{user.chinaname} 正在注册一个新的ASG官网账号。
</td>
</tr>
<tr style=""background-color: #0078D4"">
<td style=""padding: 0px"">
<table style=""font-family: Segoe UI, SegoeUIWF, Arial, sans-serif; border-spacing: 0px; border-collapse: collapse; width: 100%"">
<tbody>
<tr>
<td style=""font-size: 38px; color: #FFFFFF; padding: 12px 22px 4px 22px"" colspan=""3"">
注册
</td>
</tr>
<tr>
<td style=""font-size: 20px; color: #FFFFFF; padding: 0px 22px 18px 22px"" colspan=""3"">
{user.chinaname} 正在注册一个新的ASG官网账号。
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td style=""padding: 30px 20px; border-bottom-style: solid; border-bottom-color: #0078D4; border-bottom-width: 4px"">
<table style=""font-family: Segoe UI, SegoeUIWF, Arial, sans-serif; font-size: 12px; color: #333333; border-spacing: 0px; border-collapse: collapse; width: 100%"">
<tbody>
<tr>
<td style=""font-size: 12px; padding: 0px 0px 5px 0px"">
你的验证码是:{email_token}
<ul style=""font-size: 14px"">
<li style=""padding-top: 10px"">
如果你没有注册ASG官网账号请忽略此邮件。
</li>
<li>
请不要回复此邮件。如果你需要帮助,请联系我们。
</li>
<li>
请不要与他人分享此验证码。
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td style=""padding: 0px 0px 10px 0px; color: #B2B2B2; font-size: 12px"">
版权所有 ASG赛事官网
</td>
</tr>
</tbody>
</table>
</includetail>
</div>
");
return "ok!";
}
return NotFound(new error_mb { code = 404, message = "未找到用户" });
}
else
{
return BadRequest(new error_mb { code = 400, message = "人机验证未通过" });
}
}
/// <summary>
/// 根据职位获取用户
/// </summary>
/// <param name="req">用户信息</param>
/// <param name="jwtOptions"></param>
/// <returns></returns>
[Route("api/v1/getuserbyop")]
[HttpGet]
public async Task<List<post_user>> getuserbyop(string opname)
{
var opuser = userManager.Users.Where(x => x.officium == opname).ToList();
List<post_user> user = new List<post_user>();
foreach (var auser in opuser)
{
bool isadmin = await userManager.IsInRoleAsync(auser, "admin");
var roles = await userManager.GetRolesAsync(auser);
user.Add(new post_user { id = auser.Id, chinaname = auser.chinaname, name = auser.UserName, isadmin = isadmin, email = auser.Email,qqnumber=auser.qqnumber, Roles = (List<string>)roles });
}
return user;
}
/// <summary>
/// 登陆
/// </summary>
/// <param name="req">用户信息</param>
/// <param name="jwtOptions"></param>
/// <returns></returns>
[Route("api/v1/login")]
[HttpPost]
public async Task<ActionResult<newuser_get>> login1([FromBody] LoginRequest req, [FromServices] IOptions<JWTOptions> jwtOptions)
{
string userName = req.UserName;
string password = req.Password;
var user = await userManager.FindByNameAsync(userName);
if (user == null)
{
return NotFound(new error_mb { code = 404, message = "用户未找到" });
}
var success = await userManager.CheckPasswordAsync(user, password);
if (!success)
{
await userManager.AccessFailedAsync(user);
return BadRequest(new error_mb { code = 400, message = "密码错误" });
}
if (await userManager.IsLockedOutAsync(user))
{
return BadRequest(new error_mb { code = 400, message = "账号被锁定" });
}
if (user.Integral == null)
{
user.Integral = 0;
await userManager.UpdateAsync(user);
}
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
claims.Add(new Claim(ClaimTypes.Name, user.UserName));
var roles = await userManager.GetRolesAsync(user);
foreach (string role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
string jwtToken = BuildToken(claims, jwtOptions.Value);
return Ok(jwtToken);
}
/// <summary>
/// 登陆
/// </summary>
/// <param name="req">用户信息</param>
/// <param name="jwtOptions"></param>
/// <returns></returns>
[Route("api/v1/email_login")]
[HttpPost]
public async Task<ActionResult<newuser_get>> login2([FromBody] LoginRequest_2 req, [FromServices] IOptions<JWTOptions> jwtOptions)
{
string userEmail = req.UserEmail;
string password = req.Password;
var user = await userManager.FindByEmailAsync(userEmail);
if (user == null)
{
return NotFound(new error_mb { code = 404, message = "用户未找到" });
}
var success = await userManager.CheckPasswordAsync(user, password);
if (!success)
{
await userManager.AccessFailedAsync(user);
return BadRequest(new error_mb { code = 400, message = "密码错误!" });
}
if (await userManager.IsLockedOutAsync(user))
{
return BadRequest(new error_mb { code = 400, message = "账号被锁定" });
}
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
claims.Add(new Claim(ClaimTypes.Name, user.UserName));
var roles = await userManager.GetRolesAsync(user);
foreach (string role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
string jwtToken = BuildToken(claims, jwtOptions.Value);
return Ok(jwtToken);
}
private static string BuildToken(IEnumerable<Claim> claims, JWTOptions options)
{
DateTime expires = DateTime.Now.AddSeconds(options.ExpireSeconds);
byte[] keyBytes = Encoding.UTF8.GetBytes(options.SigningKey);
var secKey = new SymmetricSecurityKey(keyBytes);
var credentials = new SigningCredentials(secKey,
SecurityAlgorithms.HmacSha256Signature);
var tokenDescriptor = new JwtSecurityToken(expires: expires,
signingCredentials: credentials, claims: claims);
return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
}
}
}