309 lines
13 KiB
C#
309 lines
13 KiB
C#
using Dapper;
|
||
using Dapper.Contrib.Extensions;
|
||
using MailKit.Security;
|
||
using Microsoft.AspNetCore.Cors;
|
||
using Microsoft.AspNetCore.Hosting.Server;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Data.SqlClient;
|
||
using Microsoft.Extensions.Options;
|
||
using MimeKit;
|
||
using Newtonsoft.Json;
|
||
using System.DirectoryServices;
|
||
using System.DirectoryServices.AccountManagement;
|
||
using System.DirectoryServices.Protocols;
|
||
using System.Net;
|
||
using System.Runtime.Versioning;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
using static ad_login.Controllers.ApiController;
|
||
using static DbTableClass;
|
||
|
||
namespace ad_login.Controllers
|
||
{
|
||
[EnableCors("any")]
|
||
[Route("adApi")]
|
||
|
||
public class AdApiController : ControllerBase
|
||
{
|
||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||
private readonly IWebHostEnvironment _hostingEnvironment;
|
||
private readonly PasswordManagementService _passwordManagement;
|
||
private readonly string _ldapServer;
|
||
private readonly string _domain;
|
||
private readonly string _baseDn;
|
||
|
||
DbConn dbConn = new DbConn();
|
||
SqlConnection conn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:SQLConnectionString"));
|
||
|
||
|
||
public AdApiController(IHttpContextAccessor httpContextAccessor, IWebHostEnvironment webHostEnvironment, PasswordManagementService passwordManagement, IOptions<LdapSettings> ldapSettings)
|
||
{
|
||
this._httpContextAccessor = httpContextAccessor;
|
||
this._hostingEnvironment = webHostEnvironment;
|
||
this._passwordManagement = passwordManagement;
|
||
this._ldapServer = ldapSettings.Value.Server;
|
||
this._domain = ldapSettings.Value.Domain;
|
||
this._baseDn = ldapSettings.Value.BaseDn;
|
||
}
|
||
|
||
[EnableCors("any")]
|
||
[Route("resetPassword")]
|
||
[SupportedOSPlatform("windows")]
|
||
public ActionResult ResetPassword(IFormCollection obj)
|
||
{
|
||
Result ret = new Result();
|
||
|
||
string new_password = obj["new_password"].ToString();
|
||
string token = obj["token"].ToString();
|
||
|
||
if (new_password == "")
|
||
{
|
||
ret.message = "new_password is null";
|
||
ret.err_code = "1003";
|
||
ret.ret = "no";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
mailToken objMailToken = conn.QueryFirstOrDefault<mailToken>("select * from mailToken where mailToken_value=@mailToken_value and mailToken_useed='N' and mailToken_endDate>=getdate()", new { mailToken_value = token });
|
||
|
||
if (objMailToken == null)
|
||
{
|
||
ret.ret = "no";
|
||
ret.err_code = "1001";
|
||
ret.message = "token無效或過期,或是已經變更密碼過了,請重新申請忘記密碼步驟";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
|
||
try {
|
||
DirectoryEntry entry = new DirectoryEntry($"LDAP://{_ldapServer}/{_baseDn}", GlobalClass.appsettings("LdapSettings:User"), GlobalClass.appsettings("LdapSettings:Password")); // 使用 LDAP 伺服器和基礎 DN 建立 DirectoryEntry 物件。
|
||
DirectorySearcher mySearcher = new DirectorySearcher(entry);
|
||
mySearcher.Filter = ("(&(objectClass=user)(sAMAccountName=" + objMailToken.mailToken_account + "))");
|
||
|
||
SearchResult searchResult = mySearcher.FindOne();
|
||
DirectoryEntry userEntry = searchResult.GetDirectoryEntry();
|
||
userEntry.Invoke("SetPassword", new object[] { new_password });
|
||
|
||
ret.ret = "yes";
|
||
|
||
objMailToken.mailToken_useed = "Y";
|
||
|
||
conn.Update<mailToken>(objMailToken);
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
|
||
} catch (Exception ex) {
|
||
ret.ret = "no";
|
||
ret.err_code = "1002";
|
||
ret.message = "修改密碼失敗,請聯絡系統管理員 原因為" + ex.Message;
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
|
||
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
[EnableCors("any")]
|
||
[Route("forgetPassword")]
|
||
[SupportedOSPlatform("windows")]
|
||
public async Task<ActionResult> ForgetPasswordAsync(IFormCollection obj)
|
||
{
|
||
Result ret = new Result();
|
||
string userEmail = obj["userEmail"].ToString();
|
||
string userAccount = obj["userAccount"].ToString();
|
||
|
||
|
||
if (userAccount == "")
|
||
{
|
||
ret.message = "userAccount is null";
|
||
ret.err_code = "1003";
|
||
ret.ret = "no";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
if (userEmail == "")
|
||
{
|
||
ret.message = "userEmail is null";
|
||
ret.err_code = "1004";
|
||
ret.ret = "no";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, _domain, _baseDn, GlobalClass.appsettings("LdapSettings:User"), GlobalClass.appsettings("LdapSettings:Password")))
|
||
{
|
||
UserPrincipal user = UserPrincipal.FindByIdentity(pc, userAccount);
|
||
if (user != null)
|
||
{
|
||
|
||
if (user.Enabled == false)
|
||
{
|
||
ret.message = "此帳號已被停用";
|
||
ret.err_code = "1007";
|
||
ret.ret = "no";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
string emailaddress = user.EmailAddress ?? "";
|
||
|
||
if (emailaddress != userEmail)
|
||
{
|
||
ret.message = "帳號與Email不符,不是公司發給此帳號的Email";
|
||
ret.err_code = "1005";
|
||
ret.ret = "no";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
mailToken objMailToken = new mailToken();
|
||
objMailToken.mailToken_value = GlobalClass.CreateRandomCode(24);
|
||
objMailToken.mailToken_mail = userEmail;
|
||
objMailToken.mailToken_endDate = DateTime.Now.AddHours(12);
|
||
objMailToken.mailToken_account = userAccount;
|
||
|
||
conn.Insert<mailToken>(objMailToken);
|
||
|
||
string htmlBody = "";
|
||
|
||
htmlBody += "<H2>重設登入PC或公槽密碼確認信</H2>";
|
||
htmlBody += "<br/>如果您有重設登入PC或公槽密碼需求的話,請點下面連結開始網頁重設密碼。如果沒有請忽略此信!";
|
||
htmlBody += "<br/><br/>重設密碼連結:<a href='" + "https://ad-pass.bremen.com.tw/Home/reset?token=" + objMailToken.mailToken_value + "' target='_blank'>" + "https://ad-pass.bremen.com.tw/Home/reset?token=" + objMailToken.mailToken_value + "</a>";
|
||
htmlBody += "<br/><br/>PS:此連結於" + objMailToken.mailToken_endDate.ToString("yyyy/MM/dd HH:mm") + "前有效!";
|
||
|
||
MailRequest mailRequest = new MailRequest();
|
||
mailRequest.ToEmail = userEmail;
|
||
|
||
mailRequest.Body = htmlBody;
|
||
|
||
mailRequest.Subject = "重設登入PC或公槽密碼確認信";
|
||
|
||
await SendEmailAsync(mailRequest);
|
||
|
||
ret.ret = "yes";
|
||
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
else
|
||
{
|
||
ret.message = "User not found";
|
||
ret.err_code = "1006";
|
||
ret.ret = "no";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
}
|
||
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
[EnableCors("any")]
|
||
[Route("aduserList")]
|
||
[SupportedOSPlatform("windows")]
|
||
public ActionResult AduserList(IFormCollection obj) {
|
||
|
||
Result ret = new Result();
|
||
|
||
string query_token = obj["query_token"].ToString();
|
||
|
||
if (query_token == "") {
|
||
ret.message = "query_token is null";
|
||
ret.err_code = "1001";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
if (query_token != GlobalClass.appsettings("LdapSettings:query_token"))
|
||
{
|
||
ret.message = "query_token is wrong";
|
||
ret.err_code = "1002";
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
List<String> expiringUsers = [];
|
||
|
||
DirectoryEntry entry = new DirectoryEntry($"LDAP://{_ldapServer}/{_baseDn}", GlobalClass.appsettings("LdapSettings:User"), GlobalClass.appsettings("LdapSettings:Password")); // 使用 LDAP 伺服器和基礎 DN 建立 DirectoryEntry 物件。
|
||
DirectorySearcher mySearcher = new DirectorySearcher(entry);
|
||
mySearcher.Filter = "(&(objectCategory=person)(objectClass=user))"; // 篩選有「上次密碼設定時間」、「Mail」的「使用者」。
|
||
// 電子郵件
|
||
|
||
foreach (SearchResult result in mySearcher.FindAll())
|
||
{
|
||
string userSAMAccountName = result.Properties["sAMAccountName"][0].ToString() ?? string.Empty; // AD 帳號
|
||
string userDisplayName = "";
|
||
string userMail = "";
|
||
if (result.Properties["displayName"].Count > 0)
|
||
userDisplayName = result.Properties["displayName"][0].ToString();
|
||
else
|
||
userDisplayName = userSAMAccountName; // 顯示名稱
|
||
|
||
if (result.Properties["mail"].Count > 0) {
|
||
userMail = result.Properties["mail"][0].ToString() ?? string.Empty;
|
||
}
|
||
|
||
int flags = (int)result.Properties["userAccountControl"][0];
|
||
string expiringUsersInfo = $"{userSAMAccountName};{userDisplayName};{userMail}";
|
||
|
||
adUser adUser = new adUser
|
||
{
|
||
userAccount = userSAMAccountName,
|
||
userDisplayName = userDisplayName,
|
||
userMail = userMail
|
||
};
|
||
|
||
if (!Convert.ToBoolean(flags & 0x0002) && (userMail != "")) {
|
||
ret.data.Add(adUser); // 如果帳號沒有被停用,且有電子郵件,就加入結果列表。
|
||
}
|
||
}
|
||
|
||
ret.ret = "yes";
|
||
|
||
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
|
||
}
|
||
|
||
public async Task SendEmailAsync(MailRequest mailRequest)
|
||
{
|
||
var email = new MimeMessage();
|
||
email.Sender = MailboxAddress.Parse(GlobalClass.appsettings("MailServer:smtp_username"));
|
||
email.To.Add(MailboxAddress.Parse(GlobalClass.appsettings("MailServer:smtp_username")));
|
||
|
||
foreach (string item in mailRequest.ToEmail.Split(','))
|
||
{
|
||
email.Bcc.Add(MailboxAddress.Parse(item));
|
||
}
|
||
|
||
email.Subject = "重設登入PC或公槽密碼確認信";
|
||
|
||
var builder = new BodyBuilder();
|
||
|
||
if (mailRequest.attach != null)
|
||
{
|
||
builder.Attachments.Add(mailRequest.attachName, mailRequest.attach);
|
||
}
|
||
|
||
builder.HtmlBody = mailRequest.Body;
|
||
email.Body = builder.ToMessageBody();
|
||
|
||
using var smtp = new MailKit.Net.Smtp.SmtpClient();
|
||
smtp.Connect(GlobalClass.appsettings("MailServer:smtp_host"), int.Parse(GlobalClass.appsettings("MailServer:smtp_port")), SecureSocketOptions.StartTls);
|
||
smtp.Authenticate(GlobalClass.appsettings("MailServer:smtp_username"), GlobalClass.appsettings("MailServer:smtp_password"));
|
||
await smtp.SendAsync(email);
|
||
smtp.Dispose();
|
||
|
||
}
|
||
|
||
public class Result
|
||
{
|
||
public string ret = "no";
|
||
public string err_code = "0000";
|
||
public string message = "";
|
||
public List<adUser> data = new List<adUser>();
|
||
}
|
||
|
||
public class adUser
|
||
{
|
||
public string userAccount { get; set; } = string.Empty; // AD 帳號
|
||
public string userDisplayName { get; set; } = string.Empty; // 顯示名稱
|
||
public string userMail { get; set; } = string.Empty; // 電子郵件
|
||
}
|
||
|
||
}
|
||
}
|