xf 2 年之前
父节点
当前提交
1bb71c020c

+ 23 - 4
src/CallCenter.Api/Controllers/HomeController.cs

@@ -1,4 +1,5 @@
-using CallCenter.Api.Token;
+using System.Security.Claims;
+using CallCenter.Api.Token;
 using CallCenter.BlackLists;
 using CallCenter.Calls;
 using CallCenter.Ivrs;
@@ -7,12 +8,15 @@ using CallCenter.Settings;
 using CallCenter.Share.Requests;
 using CallCenter.Tels;
 using CallCenter.Users;
+using IdentityModel;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
 using NETCore.Encrypt;
 using SqlSugar;
+using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
-using XF.Domain.Https;
+using XF.Domain.Options;
 
 namespace CallCenter.Api.Controllers;
 
@@ -20,11 +24,19 @@ public class HomeController : BaseController
 {
     private readonly IUserRepository _userRepository;
     private readonly ISugarUnitOfWork<CallCenterDbContext> _uow;
+    private readonly IJwtSecurity _jwtSecurity;
+    private readonly IOptionsSnapshot<IdentityConfiguration> _identityOptionsAccessor;
 
-    public HomeController(IUserRepository userRepository, ISugarUnitOfWork<CallCenterDbContext> uow)
+    public HomeController(
+        IUserRepository userRepository, 
+        ISugarUnitOfWork<CallCenterDbContext> uow,
+        IJwtSecurity jwtSecurity,
+        IOptionsSnapshot<IdentityConfiguration> identityOptionsAccessor)
     {
         _userRepository = userRepository;
         _uow = uow;
+        _jwtSecurity = jwtSecurity;
+        _identityOptionsAccessor = identityOptionsAccessor;
     }
 
     [HttpPost("login")]
@@ -35,7 +47,14 @@ public class HomeController : BaseController
         if (user is null)
             throw new UserFriendlyException("未查询到该用户");
 
-        var token = EncryptProvider.AESEncrypt(System.Text.Json.JsonSerializer.Serialize(user), Sercurity.Key);
+        //var token = EncryptProvider.AESEncrypt(System.Text.Json.JsonSerializer.Serialize(user), Sercurity.Key);
+        var jwtOptions = _identityOptionsAccessor.Value.Jwt;
+        var claims = new List<Claim>
+        {
+            //new(JwtClaimTypes.Id, account.Id),
+            new(JwtClaimTypes.Id, user.Id),
+        };
+        var token = _jwtSecurity.EncodeJwtToken(claims);
         return token;
     }
 

+ 1 - 1
src/CallCenter.Api/Controllers/TelController.cs

@@ -9,9 +9,9 @@ using CallCenter.Users;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
 using System.Transactions;
+using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Exceptions;
-using XF.Domain.Https;
 using XF.Utility.EnumExtensions;
 
 namespace CallCenter.Api.Controllers

+ 1 - 1
src/CallCenter.Api/Controllers/TestController.cs

@@ -8,8 +8,8 @@ using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
 using NewRock.Sdk;
 using NewRock.Sdk.Security;
+using XF.Domain.Authentications;
 using XF.Domain.Cache;
-using XF.Domain.Https;
 
 namespace CallCenter.Api.Controllers
 {

+ 1 - 1
src/CallCenter.Api/Controllers/UserController.cs

@@ -6,9 +6,9 @@ using CallCenter.Tels;
 using CallCenter.Users;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
+using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Exceptions;
-using XF.Domain.Https;
 
 namespace CallCenter.Api.Controllers;
 

+ 1 - 1
src/CallCenter.Api/Realtimes/CallCenterHub.cs

@@ -2,9 +2,9 @@
 using CallCenter.Realtimes;
 using CallCenter.Users;
 using Microsoft.AspNetCore.SignalR;
+using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
-using XF.Domain.Https;
 
 namespace CallCenter.Api.Realtimes;
 

+ 40 - 15
src/CallCenter.Api/StartupExtensions.cs

@@ -1,5 +1,6 @@
 using System.IdentityModel.Tokens.Jwt;
 using System.Reflection;
+using System.Text;
 using CallCenter.Api.Exceptions;
 using CallCenter.Api.Filters;
 using CallCenter.Api.Realtimes;
@@ -22,6 +23,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
 using Microsoft.IdentityModel.Tokens;
 using Serilog;
 using CallCenter.Calls;
+using XF.Domain.Options;
 
 namespace CallCenter.Api;
 
@@ -60,22 +62,45 @@ internal static class StartupExtensions
         //        d.ClientScope = "identity.admin_api";
         //    });
 
-        //JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
-        //services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
-        //    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, d =>
-        //    {
-        //        d.Authority = "http://identity.fengwo.com"; //todo
-        //        d.RequireHttpsMetadata = false;
-        //        d.TokenValidationParameters = new TokenValidationParameters
-        //        {
-        //            ValidateAudience = false
-        //        };
-        //    })
-        //    ;
+        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+            .AddJwtBearer(d =>
+            {
+                var jwtOptions = configuration.GetSection("IdentityConfiguration").Get<IdentityConfiguration>().Jwt;
+                byte[] bytes = Encoding.UTF8.GetBytes(jwtOptions.SecretKey);
+                var secKey = new SymmetricSecurityKey(bytes);
+                d.TokenValidationParameters = new()
+                {
+                    ValidateIssuer = false,
+                    ValidateAudience = false,
+                    ValidateLifetime = true,
+                    ValidateIssuerSigningKey = true,
+                    IssuerSigningKey = secKey,
+                };
+
+                //d.Audience = "hotline_api";
+                d.Events = new JwtBearerEvents
+                {
+                    OnMessageReceived = context =>
+                    {
+                        var accessToken = context.Request.Query["access_token"];
+
+                        // If the request is for our hub...
+                        var path = context.HttpContext.Request.Path;
+                        if (!string.IsNullOrEmpty(accessToken) &&
+                            (path.StartsWithSegments("/hubs/callcenter")))
+                        {
+                            // Read the token out of the query string
+                            context.Token = accessToken;
+                        }
+                        return Task.CompletedTask;
+                    }
+                };
+            })
+            ;
 
         services.AddControllers(options =>
         {
-            options.Filters.Add<TempTokenFilter>();
+            //options.Filters.Add<TempTokenFilter>();
             options.Filters.Add<UnifyResponseFilter>();
             options.Filters.Add<UserFriendlyExceptionFilter>();
         });
@@ -182,9 +207,9 @@ internal static class StartupExtensions
 
         app.UseCors(CorsOrigins);
 
-        //app.UseAuthentication();
+        app.UseAuthentication();
         app.UseAuthorization();
-        //app.MapHub<CallCenterHub>("/hubs/callcenter");
+        app.MapHub<CallCenterHub>("/hubs/callcenter");
         //app.UseMiddleware<TempTokenMiddleware>();
 
         app.MapControllers();

+ 5 - 4
src/CallCenter.Api/Token/DefaultSessionContext.cs

@@ -1,7 +1,8 @@
 using System.Security.Authentication;
 using System.Security.Claims;
+using IdentityModel;
+using XF.Domain.Authentications;
 using XF.Domain.Dependency;
-using XF.Domain.Https;
 
 namespace CallCenter.Api.Token
 {
@@ -15,9 +16,9 @@ namespace CallCenter.Api.Token
             //var a = Thread.CurrentPrincipal as ClaimsPrincipal;
             var user = httpContext.User;
             //UserId = user.Claims.FirstOrDefault(d => d.Type == "sub")?.Value ?? string.Empty;
-            UserId = user.Claims.FirstOrDefault(d => d.Type == "UserId")?.Value ?? string.Empty;
-            UserName = user.Claims.FirstOrDefault(d => d.Type == "UserName")?.Value ?? string.Empty;
-            var roles = user.Claims.FirstOrDefault(d => d.Type == "role");
+            UserId = user.Claims.FirstOrDefault(d => d.Type == JwtClaimTypes.Id)?.Value ?? string.Empty;
+            //UserName = user.Claims.FirstOrDefault(d => d.Type == "UserName")?.Value ?? string.Empty;
+            //var roles = user.Claims.FirstOrDefault(d => d.Type == "role");
         }
 
         /// <summary>

+ 28 - 0
src/CallCenter.Api/appsettings.Development.json

@@ -59,5 +59,33 @@
     "WorkDay": [ 1, 2, 3, 4, 5, 0, 6 ],
     "WorkCategory": "08da9b9f-a35d-4ade-8ea7-55e8abbcdefd",
     "RestCategory": "08daa5f5-ac7a-4ced-8295-1c78baa15f9e"
+  },
+  "IdentityConfiguration": {
+    "Password": {
+      "RequiredLength": 8,
+      "RequireNonAlphanumeric": true,
+      "RequireLowercase": true,
+      "RequireUppercase": true
+    },
+    "User": {
+      "RequireUniqueEmail": false
+    },
+    "SignIn": {
+      "RequireConfirmedAccount": false
+    },
+    "Lockout": {
+      "MaxFailedAccessAttempts": 5,
+      "DefaultLockoutTimeSpan": "00:10:00"
+    },
+    "Account": {
+      "DefaultPassword": "Fwkj@789"
+    },
+    "Jwt": {
+      "SecretKey": "e660d04ef1d3410798c953f5d7b8a4e1",
+      "Issuer": "hotline_server",
+      "Audience": "hotline",
+      "Scope": "hotline_api",
+      "Expired": 86400 //seceonds
+    }
   }
 }

+ 29 - 1
src/CallCenter.Api/appsettings.json

@@ -24,7 +24,7 @@
           "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
           "theme": "Serilog.Sinks.SystemConsole.Themes.ConsoleTheme::None, Serilog.Sinks.Console"
         }
-      },
+      }
       //{
       //  "Name": "File",
       //  "Args": {
@@ -63,5 +63,33 @@
   "RecordSettings": {
     "Remote": "http://192.168.100.100/mcc/Recorder/",
     "Local": "http://192.168.100.36:50001/Recorder/"
+  },
+  "IdentityConfiguration": {
+    "Password": {
+      "RequiredLength": 8,
+      "RequireNonAlphanumeric": true,
+      "RequireLowercase": true,
+      "RequireUppercase": true
+    },
+    "User": {
+      "RequireUniqueEmail": false
+    },
+    "SignIn": {
+      "RequireConfirmedAccount": false
+    },
+    "Lockout": {
+      "MaxFailedAccessAttempts": 5,
+      "DefaultLockoutTimeSpan": "00:10:00"
+    },
+    "Account": {
+      "DefaultPassword": "Fwkj@789"
+    },
+    "Jwt": {
+      "SecretKey": "e660d04ef1d3410798c953f5d7b8a4e1",
+      "Issuer": "hotline_server",
+      "Audience": "hotline",
+      "Scope": "hotline_api",
+      "Expired": 86400 //seceonds
+    }
   }
 }

+ 77 - 0
src/XF.Domain/Authentications/IJwtSecurity.cs

@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.Linq;
+using System.Security.Authentication;
+using System.Security.Claims;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using Microsoft.IdentityModel.Tokens;
+using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
+using XF.Domain.Options;
+
+namespace XF.Domain.Authentications
+{
+    public interface IJwtSecurity
+    {
+        string EncodeJwtToken(ICollection<Claim> claims);
+        void DecodeJwtToken(string jwt);
+    }
+
+    public class JwtSecurity : IJwtSecurity, IScopeDependency
+    {
+        private readonly IOptions<IdentityConfiguration> _jwtConfigOptionAccessor;
+        private readonly IHttpContextAccessor _contextAccessor;
+
+        public JwtSecurity(IOptions<IdentityConfiguration> jwtConfigOptionAccessor, IHttpContextAccessor contextAccessor)
+        {
+            _jwtConfigOptionAccessor = jwtConfigOptionAccessor;
+            _contextAccessor = contextAccessor;
+        }
+
+        public string EncodeJwtToken(ICollection<Claim> claims)
+        {
+            var jwtOptions = _jwtConfigOptionAccessor.Value.Jwt;
+            if (jwtOptions == null)
+                throw new ArgumentNullException(nameof(jwtOptions));
+
+            var bytes = Encoding.UTF8.GetBytes(jwtOptions.SecretKey);
+            var securityKey = new SymmetricSecurityKey(bytes);
+            var signingCredentials =
+                new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
+            var expired = DateTime.Now.AddMinutes(jwtOptions.Expired);
+            var jwtSecurityToken = new JwtSecurityToken(jwtOptions.Issuer, jwtOptions.Audience, claims, DateTime.Now, expired,
+                signingCredentials);
+            var tokenHandler = new JwtSecurityTokenHandler();
+            var token = tokenHandler.WriteToken(jwtSecurityToken);
+            return token;
+        }
+
+        public void DecodeJwtToken(string jwt)
+        {
+            var jwtOptions = _jwtConfigOptionAccessor.Value.Jwt;
+            if (jwtOptions == null)
+                throw new ArgumentNullException(nameof(jwtOptions));
+
+            JwtSecurityTokenHandler tokenHandler = new();
+            TokenValidationParameters valParam = new();
+            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecretKey));
+            valParam.IssuerSigningKey = securityKey;
+            valParam.ValidateIssuer = false;
+            valParam.ValidateAudience = false;
+            ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwt, valParam, out SecurityToken secToken);
+            //foreach (var claim in claimsPrincipal.Claims)
+            //{
+            //    Console.WriteLine($"{claim.Type}={claim.Value}");
+
+            //}
+            if (_contextAccessor.HttpContext is null)
+                throw new AuthenticationException($"{nameof(_contextAccessor.HttpContext)} is null");
+            _contextAccessor.HttpContext.User = claimsPrincipal;
+        }
+    }
+}

+ 1 - 1
src/XF.Domain/Authentications/ISessionContext.cs

@@ -1,6 +1,6 @@
 using System.Security.Authentication;
 
-namespace XF.Domain.Https;
+namespace XF.Domain.Authentications;
 
 public interface ISessionContext
 {

+ 14 - 0
src/XF.Domain/Options/DatabaseOptions.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace XF.Domain.Options
+{
+    public class DatabaseOptions
+    {
+        public bool ApplyDbMigrations { get; set; }
+        public bool ApplySeed { get; set; }
+    }
+}

+ 29 - 0
src/XF.Domain/Options/IdentityConfiguration.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+
+namespace XF.Domain.Options
+{
+    public class IdentityConfiguration : IdentityOptions
+    {
+        public AccountOptions Account { get; set; }
+        public JwtOptions Jwt { get; set; }
+    }
+
+    public class AccountOptions
+    {
+        public string DefaultPassword { get; set; }
+    }
+
+    public class JwtOptions
+    {
+        public string SecretKey { get; set; }
+        public string Issuer { get; set; }
+        public string Audience { get; set; }
+        public string Scope { get; set; }
+        public int Expired { get; set; }
+    }
+}