diff --git a/Back/Back.csproj b/Back/Back.csproj index fe98d24..69ae328 100644 --- a/Back/Back.csproj +++ b/Back/Back.csproj @@ -26,7 +26,6 @@ - diff --git a/Back/Controllers/BaseController.cs b/Back/Controllers/BaseController.cs index e61cb5b..ac83cc0 100644 --- a/Back/Controllers/BaseController.cs +++ b/Back/Controllers/BaseController.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Shared.DTOs; +using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database; namespace Back.Controllers { @@ -59,7 +60,7 @@ namespace Back.Controllers [HttpPost("CreateCsrAndPrivateKey")] public async Task> CreateCsrAndPrivateKey(CsrPrivateKeyDto model) { - var resultValidationmodel = await _mobilevalidation.ValidateAsync(model.Mobile); + var resultValidationmodel = await _mobilevalidation.ValidateAsync(Tuple.Create(model.Mobile,false)); if (!resultValidationmodel.IsValid) return BadRequest(resultValidationmodel.Errors.Select(s => s.ErrorMessage).ToList()); return Ok(await _sBase.CreateCsrAndPrivateKey(model)); @@ -167,6 +168,23 @@ namespace Back.Controllers } } + [HttpPost("ForgetPassWord")] + [AllowAnonymous] + public async Task> ForgetPassWord(ForgetPasswordItem Item) + { + var resultValidationmodel = await _mobilevalidation.ValidateAsync(Tuple.Create(Item.Username, true)); + if (!resultValidationmodel.IsValid) + return BadRequest(resultValidationmodel.Errors.Select(s => s.ErrorMessage).ToList()); + var ID = await _servValidatinMsg.GenerateCode(new VerificationCode + { + prm = Item.Username, + val = Item.PassWord, + Type = "ForgetPassword" + }); + + _servSendMsg.Authentication(Item.Username, ID.ToString()); + return Ok(ID); + } } } diff --git a/Back/Controllers/CompanyController.cs b/Back/Controllers/CompanyController.cs new file mode 100644 index 0000000..0491279 --- /dev/null +++ b/Back/Controllers/CompanyController.cs @@ -0,0 +1,29 @@ +using Back.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Shared.DTOs; + +namespace Back.Controllers +{ + [Route("api/[controller]")] + [Authorize] + [ApiController] + public class CompanyController : ControllerBase + { + private readonly servCompany _servCompany; + public CompanyController(servCompany servCompany) + { + _servCompany = servCompany; + } + [HttpPost("ChangeLogo")] + public async Task> ChangeLogo(byte[] logo) + { + //var result = await _sBase.ReadPublicKeyFromCER(modelfromBase64); + //if (result.type == "error") + // return BadRequest(); + + return Ok(); + } + } +} diff --git a/Back/Controllers/TicketController.cs b/Back/Controllers/TicketController.cs index 853d7e4..4212ade 100644 --- a/Back/Controllers/TicketController.cs +++ b/Back/Controllers/TicketController.cs @@ -2,6 +2,7 @@ using Back.Data.Models; using Back.Services; using Back.Validations; +using FluentValidation; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -33,7 +34,7 @@ namespace Back.Controllers [AllowAnonymous] public async Task> NewTicketNoAuthentication(CTicketNoAuthenticationDto item) { - var resultValidationmodel = await _mobilevalidation.ValidateAsync(item.Mobile); + var resultValidationmodel = await _mobilevalidation.ValidateAsync(Tuple.Create(item.Mobile,false)); if (!resultValidationmodel.IsValid) return BadRequest(resultValidationmodel.Errors.Select(s => s.ErrorMessage).ToList()); diff --git a/Back/Controllers/UserController.cs b/Back/Controllers/UserController.cs index 6694920..72a3e99 100644 --- a/Back/Controllers/UserController.cs +++ b/Back/Controllers/UserController.cs @@ -37,6 +37,19 @@ namespace Back.Controllers return Ok(result); } + [HttpPost("ChangePassword")] + public async Task> ChangePassword(ChangePasswordDto item) + { + if (item.newPass.Trim() != item.renewPass.Trim()) + return BadRequest(new List { "تکرار کلمه عبور با کلمه عبور مطابقت ندارد" }); + if (item.newPass.Trim().Length <= 3) + return BadRequest(new List { "کلمه عبور جدید باید بیشتر از 3کاراکتر باشد" }); + var UserID = HttpContext.User.Claims.First(c => c.Type == "UserID").Value; + if (!await _servUser.PermissionChangePassword(item.oldPass.Trim(), Convert.ToInt32(UserID))) + return BadRequest(new List { "کلمه عبور قبلی صحیح نمی باشد" }); + return Ok(await _servUser.ChangePassword(item.newPass.Trim(), Convert.ToInt32(UserID))); + + } diff --git a/Back/Controllers/VerificationController.cs b/Back/Controllers/VerificationController.cs index 78429ec..1fed6bf 100644 --- a/Back/Controllers/VerificationController.cs +++ b/Back/Controllers/VerificationController.cs @@ -17,13 +17,15 @@ namespace Back.Controllers private readonly GetVerificationValidation _getVerificationValidation; private readonly servSendMsg _servSendMsg; private readonly servCompany _servCompany; + private readonly servUser _servUser; public VerificationController(ServValidatinMsg servValidatinMsg, GetVerificationValidation getVerificationValidation - , servCompany servCompany, servSendMsg servSendMsg) + , servCompany servCompany, servSendMsg servSendMsg, servUser servUser) { _servValidatinMsg = servValidatinMsg; _getVerificationValidation = getVerificationValidation; _servCompany = servCompany; _servSendMsg = servSendMsg; + _servUser = servUser; } [HttpGet("GetVerification/{ID}")] [AllowAnonymous] @@ -61,6 +63,12 @@ namespace Back.Controllers _servSendMsg.Authentication(company.Mobile, ID.ToString()); break; + + case "ForgetPassword": + var user = await _servUser.ChangePasswordByMobile(_getVerificationValidation.verificationCode.prm, _getVerificationValidation.verificationCode.val); + _servSendMsg.Authentication(_getVerificationValidation.verificationCode.prm, ID.ToString()); + break; + default: return BadRequest("این نوع احراز تعریف نشده"); } diff --git a/Back/Features/CheckOnlineUser.cs b/Back/Features/CheckOnlineUser.cs new file mode 100644 index 0000000..dd13de4 --- /dev/null +++ b/Back/Features/CheckOnlineUser.cs @@ -0,0 +1,50 @@ +using Back.Services; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Net; +using System.Threading.Tasks; + + +namespace Back.Features +{ + // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project + public class CheckOnlineUser + { + private readonly RequestDelegate _next; + + public CheckOnlineUser(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext httpContext) + { + int UserID = Convert.ToInt32(httpContext.User.Claims.Where(w => w.Type == "UserID").Select(s => s.Value).FirstOrDefault()); + var accessToken = httpContext.GetTokenAsync("access_token").Result; + if (UserID==null || UserID==0 || string.IsNullOrEmpty(accessToken)) + await _next(httpContext); + else + { + servUser _servUser = (servUser)httpContext.RequestServices.GetService(typeof(servUser)); + var user = _servUser.GetUserByUserID(UserID).Result; + if (user.Token==accessToken) + await _next(httpContext); + else + { + httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; + } + } + } + } + + // Extension method used to add the middleware to the HTTP request pipeline. + public static class CheckOnlineUserExtensions + { + public static IApplicationBuilder UseCheckOnlineUser(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} diff --git a/Back/Program.cs b/Back/Program.cs index 3b3a30d..1d4a754 100644 --- a/Back/Program.cs +++ b/Back/Program.cs @@ -1,6 +1,7 @@ using Back; using Back.Data.Contracts; using Back.Data.Infrastructure.Repository; +using Back.Features; using Back.Services; using Back.Validations; using Microsoft.EntityFrameworkCore; @@ -80,7 +81,7 @@ app.UseHttpsRedirection(); app.UseCors(origins); app.UseAuthentication(); app.UseAuthorization(); - +app.UseCheckOnlineUser(); app.MapControllers(); app.Run(); diff --git a/Back/Services/servCompany.cs b/Back/Services/servCompany.cs index c4be416..4e05919 100644 --- a/Back/Services/servCompany.cs +++ b/Back/Services/servCompany.cs @@ -103,9 +103,9 @@ namespace Back.Services public async Task ExistMobileAndCompanyIsActive(string mobile) { return await _repoCompany.GetAll().AnyAsync(w => w.Mobile == mobile && w.IsActive); - } + } + - } diff --git a/Back/Services/servUser.cs b/Back/Services/servUser.cs index d40d33f..ce67ff8 100644 --- a/Back/Services/servUser.cs +++ b/Back/Services/servUser.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Shared.DTOs; using System.IdentityModel.Tokens.Jwt; +using System.Reflection; using System.Security.Claims; using System.Text; @@ -56,7 +57,7 @@ namespace Back.Services return null; string Jwt_Lifetime_Minutes = await GetJwt_Lifetime_Minutes(); - + ret.UserName = user.Username; ret.Token =newtoken ? await CerateToken(user.ID, user.Username, Jwt_Lifetime_Minutes) : user.Token; ret.FullName = user.Fullname; ret.Photo = user.Photo==null ? null : Convert.ToBase64String(user.Photo); @@ -175,7 +176,14 @@ namespace Back.Services await _RepoUser.UpdateAsync(user); } } - + public async Task ChangePasswordByMobile(string mobile, string newpassword) + { + var user =await GetUserByUsername(mobile); + if (user == null) + return false; + user.Password = newpassword.encrypted(); + return await _RepoUser.UpdateAsync(user); + } public async Task GetDashBoard(int CompanyID,int UserID) { DashBoardDTO request=new DashBoardDTO(); @@ -237,6 +245,19 @@ namespace Back.Services //}); return await _RepoUser.UpdateByObjAsync(user); } + public async Task ChangePassword(string newPass, int UserID) + { + var user = await GetUserByUserID(UserID); + if (user == null) + return false; + user.Password = newPass.encrypted(); + return await _RepoUser.UpdateAsync(user); + } + public async Task PermissionChangePassword(string oldPass,int UserID) + { + return await _RepoUser.GetAll().AnyAsync(w => w.ID == UserID && w.Password==oldPass.encrypted() && w.IsActive); + + } //--------internal private async Task GetJwt_Lifetime_Minutes() { diff --git a/Back/Validations/MobileValidation.cs b/Back/Validations/MobileValidation.cs index ea1b4e7..c42c150 100644 --- a/Back/Validations/MobileValidation.cs +++ b/Back/Validations/MobileValidation.cs @@ -1,19 +1,33 @@ -using FluentValidation; +using Back.Services; +using FluentValidation; using Shared.DTOs; using System; namespace Back.Validations { - public class MobileValidation : AbstractValidator + public class MobileValidation : AbstractValidator> { - public MobileValidation() + public MobileValidation(servCompany servCompany) { CascadeMode = CascadeMode.Stop; - RuleFor(m => m) + RuleFor(m => m.Item1) .NotEmpty().WithMessage("موبایل نمی تواند باشد") .NotNull().WithMessage("موبایل نمی تواند باشد") .Length(11).WithMessage("فرمت موبایل صحیح نمی باشد") .Must(m => m.StartsWith("09")).WithMessage("فرمت موبایل صحیح نمی باشد"); + RuleFor(m => m) + .Custom((model, context) => { + if (model.Item2) + { + if (!servCompany.ExistMobileAndCompanyIsActive(model.Item1).Result) + { + context.AddFailure("این موبایل یافت نشد"); + } + } + + + + }); } } } diff --git a/Back/appsettings.Development.json b/Back/appsettings.Development.json index 2ceab23..eedadbc 100644 --- a/Back/appsettings.Development.json +++ b/Back/appsettings.Development.json @@ -10,6 +10,6 @@ }, "Fixedvalues": { - "Jwt_Lifetime_Minutes": "60" + "Jwt_Lifetime_Minutes": "144000" } } diff --git a/Shared/DTOs/ChangePasswordDto.cs b/Shared/DTOs/ChangePasswordDto.cs new file mode 100644 index 0000000..77fec64 --- /dev/null +++ b/Shared/DTOs/ChangePasswordDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Shared.DTOs +{ + public class ChangePasswordDto + { + public string oldPass { get; set; } + public string newPass { get; set; } + public string renewPass { get; set; } + } +} diff --git a/Shared/DTOs/ForgetPasswordItem.cs b/Shared/DTOs/ForgetPasswordItem.cs new file mode 100644 index 0000000..5ef9603 --- /dev/null +++ b/Shared/DTOs/ForgetPasswordItem.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Shared.DTOs +{ + public class ForgetPasswordItem + { + public string Username { get; set; } + public string PassWord { get; set; } + } +} diff --git a/Shared/DTOs/UserAuthenticationDTO.cs b/Shared/DTOs/UserAuthenticationDTO.cs index 0cca5ff..efe5efe 100644 --- a/Shared/DTOs/UserAuthenticationDTO.cs +++ b/Shared/DTOs/UserAuthenticationDTO.cs @@ -4,7 +4,7 @@ namespace Shared.DTOs { public class UserAuthenticationDTO { - + public string UserName { get; set; } public string FullName { get; set; } public string Token { get; set; } public DateTime enterDate { get; set; } diff --git a/TaxPayerFull/Layout/PanelLayout.razor b/TaxPayerFull/Layout/PanelLayout.razor index 9ac5e5a..6f788e0 100644 --- a/TaxPayerFull/Layout/PanelLayout.razor +++ b/TaxPayerFull/Layout/PanelLayout.razor @@ -1,4 +1,10 @@ @inherits LayoutComponentBase +@using Front.Services +@using Shared.DTOs +@inject ILocalStorageService Storage; +@inject UserAuthenticationDTO userinfo +@inject HttpClient _hc +@inject NavigationManager nav @@ -116,33 +122,42 @@ @code{ - string[] cssActionItem = { "active", "", "", "", "", "", "" }; + string[] cssActionItem = { "active", "", "", "", "", "", "", "" }; } @functions{ diff --git a/TaxPayerFull/Pages/Sign-in.razor b/TaxPayerFull/Pages/Sign-in.razor index ffe1501..a9cbcef 100644 --- a/TaxPayerFull/Pages/Sign-in.razor +++ b/TaxPayerFull/Pages/Sign-in.razor @@ -58,7 +58,7 @@
- نام کاربری + نام کاربری(موبایل)
@@ -104,7 +104,7 @@
@@ -150,10 +150,23 @@ string alertMessage = ""; protected override async Task OnParametersSetAsync() { - if (from == "Verification") + if (from == "VerificationRegister") { ShowSuccessAlert("ثبت نام شما با موفقیت انجام شد"); } + else if (from == "VerificationFrogetPass") + { + ShowSuccessAlert("تغییر کلمه عبور با موفقیت انجام شد"); + } + else if (from == "unon") + { + ShowSuccessAlert("برای استفاده از برنامه لطفا مجدد وارد شود"); + } + else if (from == "changePass") + { + ShowSuccessAlert("کلمه عبور با موفقیت تغییر کرد"); + + } await base.OnParametersSetAsync(); } protected override async Task OnInitializedAsync() @@ -184,7 +197,36 @@ alertMessage = msg; } private async Task EndForm() => nav.NavigateTo("/"); + private async Task ForgetPass() + { + if (string.IsNullOrEmpty(Model.Username)) + { + ShowDangerAlert("لطفا نام کابری(موبایل) خود را وارد نمایید"); + } + else if (string.IsNullOrEmpty(Model.Password)) + { + ShowDangerAlert("لطفا کلمه عبور جدید را وارد نمایید"); + } + else + { + var request = await _hc.PostAsJsonAsync("Base/ForgetPassWord", new ForgetPasswordItem + { + Username = Model.Username, + PassWord = Model.Password + }); + if (request.IsSuccessStatusCode) + { + var VerificationID = await request.Content.ReadFromJsonAsync(); + nav.NavigateTo($"Verification/{VerificationID}"); + } + else + { + var error = await request.Content.ReadFromJsonAsync>(); + ShowDangerAlert(error[0]); + } + } + } private async Task OnLoginClick() { @@ -207,7 +249,7 @@ userinfo.Photo = userinfomodel.Photo; userinfo.exitDate = userinfomodel.exitDate; userinfo.enterDate = userinfomodel.enterDate; - + userinfo.UserName = userinfomodel.UserName; nav.NavigateTo("/Panel"); } diff --git a/TaxPayerFull/Pages/UserPanel/Profile.razor b/TaxPayerFull/Pages/UserPanel/Profile.razor new file mode 100644 index 0000000..2f0b4ae --- /dev/null +++ b/TaxPayerFull/Pages/UserPanel/Profile.razor @@ -0,0 +1,200 @@ +@page "/Profile" +@using Front.Services +@using Shared.DTOs +@layout PanelLayout +@inject UserAuthenticationDTO userinfo +@inject HttpClientController _hc +@inject ILocalStorageService Storage; +
+

+ متفرقه / پروفایل +

+
+ + + +
+
+
+
+
تغییر عکس
+
+
+ @{ + _src = "assets/img/avatars/1.png"; + if (userinfo.Company.Logo != null) + _src = "data:image/jpeg;base64," + @userinfo.Company.Logo; + + } + user-avatar +
+ + +

JPG، GIF یا PNG مجاز است. حداکثر اندازه @maxFileSize هزار

+
+
+
+
+
+
+
+
+
+
تغییر کلمه عبور
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
تغییر نام کاربری/ موبایل
+
+
+
+ +
+ + +
+
+ +
+ +
+
+
+
+
+
+
+
تغییر نام
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ +
+
+ + + +@code { + public string _src { get; set; } + private long maxFileSize = 1024 * 15; + [SupplyParameterFromForm] + public ChangePasswordDto changepassModel { get; set; } + // alert + AlertColor alertColor = AlertColor.Primary; + IconName alertIconName = IconName.CheckCircleFill; + bool Hidealert = true; + string alertMessage = ""; + + protected override void OnInitialized() => changepassModel ??= new(); +} +@functions{ + private void ShowDangerAlert(string msg) + { + Hidealert = false; + alertColor = AlertColor.Danger; + alertIconName = IconName.ExclamationTriangleFill; + alertMessage = msg; + } + private void ShowSuccessAlert(string msg) + { + Hidealert = false; + alertColor = AlertColor.Success; + alertIconName = IconName.CheckCircleFill; + alertMessage = msg; + } + private async Task changepassSubmit(){ + var request = await _hc.Post("User/ChangePassword", changepassModel); + if (request.IsSuccessStatusCode) + { + if (await request.Content.ReadFromJsonAsync()) + { + _hc._hc.DefaultRequestHeaders.Clear(); + await Storage.RemoveItem("token"); + userinfo.Token = ""; + _hc._nav.NavigateTo("/Sign-in/changePass"); + } + else ShowDangerAlert("خطای سیستمی"); + }else + { + var errors = await request.Content.ReadFromJsonAsync>(); + ShowDangerAlert(errors[0]); + } + } + private async Task changePic(InputFileChangeEventArgs e){ + if (e.GetMultipleFiles()[0].Size <= maxFileSize) + { + string Base64Str = ""; + byte[] Array; + using (MemoryStream stream = new MemoryStream()) + { + await e.GetMultipleFiles()[0].OpenReadStream(maxFileSize).CopyToAsync(stream); + + Array = stream.ToArray(); + Base64Str = Convert.ToBase64String(Array); + + } + + if (!string.IsNullOrEmpty(Base64Str)) + { + var request = await _hc.Post("Company/ChangeLogo", Array); + if (request.IsSuccessStatusCode) + { + userinfo.Company.Logo = _src = Base64Str; + + ShowSuccessAlert("تصویر با موفقیت تغییر کرد"); + } + else + { + ShowDangerAlert ( "خطایی در اجرای عملیات رخ داده"); + } + } + } + else + { + ShowDangerAlert ( "حجم فایل بیشتر از حد مجاز می باشد"); + } + } +} \ No newline at end of file diff --git a/TaxPayerFull/Pages/Verification.razor b/TaxPayerFull/Pages/Verification.razor index c0842e5..5a665f0 100644 --- a/TaxPayerFull/Pages/Verification.razor +++ b/TaxPayerFull/Pages/Verification.razor @@ -143,7 +143,9 @@ if (status) { if (VerificationCodeModel.Type == "CompanyRegistration") - nav.NavigateTo("/Sign-in/Verification"); + nav.NavigateTo("/Sign-in/VerificationRegister"); + else if (VerificationCodeModel.Type == "ForgetPassword") + nav.NavigateTo("/Sign-in/VerificationFrogetPass"); else nav.NavigateTo("/"); diff --git a/TaxPayerFull/Program.cs b/TaxPayerFull/Program.cs index 350ba23..251cf3a 100644 --- a/TaxPayerFull/Program.cs +++ b/TaxPayerFull/Program.cs @@ -13,6 +13,7 @@ builder.Services.AddBlazorBootstrap(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(sp => new UserAuthenticationDTO()); diff --git a/TaxPayerFull/Services/HttpClientController.cs b/TaxPayerFull/Services/HttpClientController.cs new file mode 100644 index 0000000..f9d8950 --- /dev/null +++ b/TaxPayerFull/Services/HttpClientController.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Components; +using System.Net.Http.Json; + +namespace Front.Services +{ + public class HttpClientController + { + public readonly HttpClient _hc; + public readonly NavigationManager _nav; + public HttpClientController(HttpClient hc, NavigationManager nav) + { + _hc = hc; + _nav = nav; + } + public async Task Get(string route) + { + var request = await _hc.GetAsync(route); + if (request.StatusCode==System.Net.HttpStatusCode.Unauthorized) + _nav.NavigateTo("/Sign-in/unon"); + return request; + } + public async Task Post(string route,T mode) + { + var request = await _hc.PostAsJsonAsync(route,mode); + if (request.StatusCode == System.Net.HttpStatusCode.Unauthorized) + _nav.NavigateTo("/Sign-in/unon"); + return request; + } + } +} diff --git a/TaxPayerFull/Services/MidLevel.cs b/TaxPayerFull/Services/MidLevel.cs index dcefa86..44fbc6f 100644 --- a/TaxPayerFull/Services/MidLevel.cs +++ b/TaxPayerFull/Services/MidLevel.cs @@ -31,6 +31,7 @@ namespace Front.Services _user.Photo = userinfomodel.Photo; _user.exitDate = userinfomodel.exitDate; _user.enterDate = userinfomodel.enterDate; + _user.UserName= userinfomodel.UserName; } }