Files
Wx_WxCheck_Prod/WxCheckMvc/Controllers/LoginController.cs

363 lines
16 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 Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using MySql.Data.MySqlClient;
using System;
using System.Data;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Net.Http;
using System.Text.Json;
namespace WxCheckMvc.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class LoginController : ControllerBase
{
private readonly MySqlConnection _connection;
private readonly IHttpClientFactory _httpClientFactory;
public IConfiguration? configuration { get; set; }
public LoginController(MySqlConnection connection, IHttpClientFactory httpClientFactory, IConfiguration? configuration)
{
_connection = connection;
_httpClientFactory = httpClientFactory;
this.configuration = configuration;
}
// 获取微信小程序OpenID
private async Task<string> GetWxOpenIdAsync(string code)
{
try
{
var appId = configuration["WeChat:AppId"];
var appSecret = configuration["WeChat:AppSecret"];
if (string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(appSecret))
{
throw new Exception("微信小程序配置缺失");
}
var httpClient = _httpClientFactory.CreateClient();
var url = $"https://api.weixin.qq.com/sns/jscode2session?appid={appId}&secret={appSecret}&js_code={code}&grant_type=authorization_code";
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var jsonDocument = JsonDocument.Parse(responseContent);
if (jsonDocument.RootElement.TryGetProperty("openid", out var openidElement))
{
return openidElement.GetString();
}
else
{
// 如果有错误信息,抛出异常
if (jsonDocument.RootElement.TryGetProperty("errcode", out var errcodeElement) &&
jsonDocument.RootElement.TryGetProperty("errmsg", out var errmsgElement))
{
throw new Exception($"获取OpenID失败: {errcodeElement.GetInt32()} - {errmsgElement.GetString()}");
}
throw new Exception("获取OpenID失败: 响应中未包含openid");
}
}
catch (Exception ex)
{
throw new Exception($"获取微信OpenID时发生错误: {ex.Message}");
}
}
private string GetToken(string entity)
{
string TokenString;
var claims = new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.Name, entity)
};
var secretByte = Encoding.UTF8.GetBytes(configuration["JwT:SecretKey"]);
var signingKey = new SymmetricSecurityKey(secretByte);
var a = SecurityAlgorithms.HmacSha256;
var signingCredentials = new SigningCredentials(signingKey, a);
var token = new JwtSecurityToken(
issuer: configuration["JwT:Issuer"],
audience: configuration["JwT:Audience"],//接收
claims: claims,//存放的用户信息
notBefore: DateTime.UtcNow,//发布时间
expires: DateTime.UtcNow.AddMonths(12),
signingCredentials: signingCredentials
//有效期设置为1天signingCredentials //数字名
);
TokenString = new JwtSecurityTokenHandler().WriteToken(token);
return TokenString;
}
// 用户注册接口
[HttpPost]
public async Task<IActionResult> Register([FromBody] RegisterRequest request)
{
try
{
if (_connection.State != ConnectionState.Open)
{
await _connection.OpenAsync();
}
if (string.IsNullOrEmpty(request.UserKey))
{
return BadRequest(new { success = false, message = "UserKey不能为空" });
}
// 检查用户是否存在
UserResponse user = null;
using (MySqlCommand checkCmd = new MySqlCommand("SELECT Id, UserName, UserKey, WeChatName, PhoneNumber, AvatarUrl, FirstLoginTime, IsDisabled, CreateTime, UpdateTime FROM xcx_users WHERE UserKey = @UserKey", _connection))
{
checkCmd.Parameters.AddWithValue("@UserKey", request.UserKey);
using (var reader = await checkCmd.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
user = new UserResponse
{
Id = reader.GetInt64(0),
UserName = reader.IsDBNull(1) ? "" : reader.GetString(1),
UserKey = reader.GetString(2),
WeChatName = reader.IsDBNull(3) ? "" : reader.GetString(3),
PhoneNumber = reader.IsDBNull(4) ? "" : reader.GetString(4),
AvatarUrl = reader.IsDBNull(5) ? "" : reader.GetString(5),
FirstLoginTime = reader.GetDateTime(6),
IsDisabled = reader.GetBoolean(7),
CreateTime = reader.GetDateTime(8),
UpdateTime = reader.GetDateTime(9)
};
}
}
}
if (user == null)
{
return NotFound(new { success = false, message = "用户不存在" });
}
// 在验证之前,先对 UserName 和 PhoneNumber 去除空格和标点符号
string cleanedUserName = request.UserName ?? string.Empty;
string cleanedPhoneNumber = request.PhoneNumber ?? string.Empty;
// PhoneNumber 只保留数字
cleanedPhoneNumber = Regex.Replace(cleanedPhoneNumber, "\\D", "");
// UserName 去除标点、符号和空白(保留所有字母/汉字/罕见字形以及数字)
cleanedUserName = Regex.Replace(cleanedUserName, @"[\p{P}\p{S}\s]+", "").Trim();
// 验证 UserName 不为空
if (string.IsNullOrEmpty(cleanedUserName))
{
return BadRequest(new { success = false, message = "用户名不能为空或仅包含非法字符" });
}
// 验证 PhoneNumber 是否为合法手机号(以 1 开头,共 11 位数字)
if (!Regex.IsMatch(cleanedPhoneNumber, "^1\\d{10}$"))
{
return BadRequest(new { success = false, message = "手机号格式错误" });
}
// 将清理后的值写回 request确保更新数据库时使用清理后的值
request.UserName = cleanedUserName;
request.PhoneNumber = cleanedPhoneNumber;
// 更新用户信息
using (MySqlCommand cmd = new MySqlCommand("UPDATE xcx_users SET UserName = @UserName, WeChatName = @WeChatName, PhoneNumber = @PhoneNumber, AvatarUrl = @AvatarUrl, UpdateTime = NOW() WHERE UserKey = @UserKey", _connection))
{
cmd.Parameters.AddWithValue("@UserName", request.UserName ?? (object)DBNull.Value);
cmd.Parameters.AddWithValue("@WeChatName", request.WeChatName ?? "");
cmd.Parameters.AddWithValue("@PhoneNumber", request.PhoneNumber ?? "");
cmd.Parameters.AddWithValue("@AvatarUrl", request.AvatarUrl ?? (object)DBNull.Value);
cmd.Parameters.AddWithValue("@UserKey", request.UserKey);
await cmd.ExecuteNonQueryAsync();
}
// 获取更新后的用户信息
UserResponse updatedUser = null;
using (MySqlCommand cmd = new MySqlCommand("SELECT Id, UserName, UserKey, WeChatName, PhoneNumber, AvatarUrl, FirstLoginTime, IsDisabled, CreateTime, UpdateTime FROM xcx_users WHERE UserKey = @UserKey", _connection))
{
cmd.Parameters.AddWithValue("@UserKey", request.UserKey);
using (var reader = await cmd.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
updatedUser = new UserResponse
{
Id = reader.GetInt64(0),
UserName = reader.IsDBNull(1) ? "" : reader.GetString(1),
UserKey = reader.GetString(2),
WeChatName = reader.IsDBNull(3) ? "" : reader.GetString(3),
PhoneNumber = reader.IsDBNull(4) ? "" : reader.GetString(4),
AvatarUrl = reader.IsDBNull(5) ? "" : reader.GetString(5),
FirstLoginTime = reader.GetDateTime(6),
IsDisabled = reader.GetBoolean(7),
CreateTime = reader.GetDateTime(8),
UpdateTime = reader.GetDateTime(9),
Token = GetToken(request.UserKey)
};
}
}
}
return Ok(new { success = true, data = updatedUser });
}
catch (Exception ex)
{
return StatusCode(500, new { success = false, message = "更新用户信息失败", error = ex.Message });
}
finally
{
if (_connection.State == ConnectionState.Open)
{
await _connection.CloseAsync();
}
}
}
// 用户登录接口
[HttpPost]
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
try
{
string openId;
try
{
openId = await GetWxOpenIdAsync(request.Code);
}
catch (Exception ex)
{
return BadRequest(new { success = false, message = "获取微信OpenID失败", error = ex.Message });
}
if (_connection.State != ConnectionState.Open)
{
await _connection.OpenAsync();
}
UserResponse user = null;
// 检查用户是否存在
using (MySqlCommand checkCmd = new MySqlCommand("SELECT COUNT(1) FROM xcx_users WHERE UserKey = @UserKey", _connection))
{
checkCmd.Parameters.AddWithValue("@UserKey", openId);
int count = Convert.ToInt32(await checkCmd.ExecuteScalarAsync());
// 如果用户不存在,则注册新用户
if (count == 0)
{
using (MySqlCommand insertCmd = new MySqlCommand("INSERT INTO xcx_users (UserKey, FirstLoginTime, IsDisabled, CreateTime, UpdateTime) VALUES (@UserKey, @FirstLoginTime, @IsDisabled, NOW(), NOW())", _connection))
{
insertCmd.Parameters.AddWithValue("@UserKey", openId);
insertCmd.Parameters.AddWithValue("@FirstLoginTime", DateTime.Now);
insertCmd.Parameters.AddWithValue("@IsDisabled", 0); // 默认启用
await insertCmd.ExecuteNonQueryAsync();
}
}
else
{
// 用户已存在:更新最后一次接口调用时间
using (MySqlCommand updateCmd = new MySqlCommand("UPDATE xcx_users SET UpdateTime = NOW() WHERE UserKey = @UserKey", _connection))
{
updateCmd.Parameters.AddWithValue("@UserKey", openId);
await updateCmd.ExecuteNonQueryAsync();
}
}
}
// 获取用户信息
using (MySqlCommand cmd = new MySqlCommand("SELECT Id, UserName, UserKey, WeChatName, PhoneNumber, AvatarUrl, FirstLoginTime, IsDisabled, CreateTime, UpdateTime FROM xcx_users WHERE UserKey = @UserKey", _connection))
{
cmd.Parameters.AddWithValue("@UserKey", openId);
using (var reader = await cmd.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
user = new UserResponse
{
Id = reader.GetInt64(0),
UserName = reader.IsDBNull(1) ? "" : reader.GetString(1),
UserKey = reader.GetString(2),
WeChatName = reader.IsDBNull(3) ? "" : reader.GetString(3),
PhoneNumber = reader.IsDBNull(4) ? "" : reader.GetString(4),
AvatarUrl = reader.IsDBNull(5) ? "" : reader.GetString(5),
FirstLoginTime = reader.GetDateTime(6),
IsDisabled = reader.GetBoolean(7),
CreateTime = reader.GetDateTime(8),
UpdateTime = reader.GetDateTime(9),
Token = GetToken(openId)
};
}
}
}
if (user == null)
{
return NotFound(new { success = false, message = "用户不存在" });
}
if (user.IsDisabled)
{
return Ok(new { success = false, message = "用户已被禁用" });
}
return Ok(new { success = true, data = user });
}
catch (Exception ex)
{
return StatusCode(500, new { success = false, message = "登录失败", error = ex.Message });
}
finally
{
if (_connection.State == ConnectionState.Open)
{
await _connection.CloseAsync();
}
}
}
}
// 请求和响应模型
public class RegisterRequest
{
public string UserName { get; set; }
public string UserKey { get; set; }
public string WeChatName { get; set; }
public string PhoneNumber { get; set; }
public string AvatarUrl { get; set; }
}
public class LoginRequest
{
public string Code { get; set; }
}
public class UserResponse
{
public long Id { get; set; }
public string UserName { get; set; }
public string UserKey { get; set; }
public string WeChatName { get; set; }
public string PhoneNumber { get; set; }
public string AvatarUrl { get; set; }
public DateTime FirstLoginTime { get; set; }
public bool IsDisabled { get; set; }
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public string Token { get; set; }
}
}