ke_junjie
2025-06-04 84620534eb627e95811b971a4b552b6a177829bf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
using iWare.Wms.Core;
using iWare.Wms.Core.Options;
using Furion;
using Furion.DatabaseAccessor;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.EventBus;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using UAParser;
 
namespace iWare.Wms.Application
{
    /// <summary>
    /// 登录授权相关服务
    /// </summary>
    [ApiDescriptionSettings(Name = "Auth", Order = 160)]
    [Route("api")]
    public class AuthService : IAuthService, IDynamicApiController, ITransient
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
 
        private readonly IRepository<SysUser> _sysUserRep; // 用户表仓储
        private readonly ISysUserService _sysUserService; // 系统用户服务
        private readonly ISysEmpService _sysEmpService; // 系统员工服务
        private readonly ISysRoleService _sysRoleService; // 系统角色服务
        private readonly ISysMenuService _sysMenuService; // 系统菜单服务
        private readonly ISysAppService _sysAppService; // 系统应用服务
        private readonly IClickWordCaptcha _captchaHandle; // 验证码服务
        private readonly ISysConfigService _sysConfigService; // 验证码服务
        private readonly IEventPublisher _eventPublisher;
        private readonly ISysCacheService _cache;
 
        public AuthService(IRepository<SysUser> sysUserRep, IHttpContextAccessor httpContextAccessor,
            ISysUserService sysUserService, ISysEmpService sysEmpService, ISysRoleService sysRoleService,
            ISysMenuService sysMenuService, ISysAppService sysAppService, IClickWordCaptcha captchaHandle,
            ISysConfigService sysConfigService, IEventPublisher eventPublisher, ISysCacheService cache)
        {
            _sysUserRep = sysUserRep;
            _httpContextAccessor = httpContextAccessor;
            _sysUserService = sysUserService;
            _sysEmpService = sysEmpService;
            _sysRoleService = sysRoleService;
            _sysMenuService = sysMenuService;
            _sysAppService = sysAppService;
            _captchaHandle = captchaHandle;
            _sysConfigService = sysConfigService;
            _eventPublisher = eventPublisher;
            _cache = cache;
        }
 
        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="input"></param>
        /// <remarks>默认用户名/密码:admin/admin</remarks>
        /// <returns></returns>
        [HttpPost("login")]
        [AllowAnonymous]
        public string LoginAsync([Required] LoginInput input)
        {
            // 获取加密后的密码
            var encryptPasswod = MD5Encryption.Encrypt(input.Password);
 
            // 判断用户名和密码是否正确 忽略全局过滤器
            var user = _sysUserRep
                .Where(u => u.Account.Equals(input.Account) && u.Password.Equals(encryptPasswod) && !u.IsDeleted, false, true)
                .FirstOrDefault();
            _ = user ?? throw Oops.Oh(ErrorCode.D1000);
 
            // 验证账号是否被冻结
            if (user.Status == CommonStatus.DISABLE)
                throw Oops.Oh(ErrorCode.D1017);
 
            //验证是否单用户登录,如果是剔除已经登录的用户
            if (_sysConfigService.GetEnableSingleLoginFlag().Result)
            {
                var onlineUsers = _cache.GetAsync<List<OnlineUser>>(CommonConst.CACHE_KEY_ONLINE_USER).Result;
                if (onlineUsers != null)
                {
                    var loginuser = onlineUsers.FirstOrDefault(u => u.UserId == user.Id);
                    if (loginuser != null)
                    {
                        App.GetService<ISysOnlineUserService>().SingleLoginForceExist(loginuser);
                    }
                }
            }
 
            // 员工信息
            var empInfo = _sysEmpService.GetEmpInfo(user.Id).Result;
 
            // 获取数据权限
            var dataScopes = JsonUtil.ToJson(_sysUserService.GetUserDataScopeIdList(user.Id).Result);
 
            // 生成Token令牌
            //var accessToken = await _jwtBearerManager.CreateTokenAdmin(user);
            var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
            {
                {ClaimConst.CLAINM_USERID, user.Id},
                //{ClaimConst.TENANT_ID, user.TenantId},
                {ClaimConst.CLAINM_ACCOUNT, user.Account},
                {ClaimConst.CLAINM_NAME, user.Name},
                {ClaimConst.CLAINM_SUPERADMIN, user.AdminType},
                {ClaimConst.CLAINM_ORGID, empInfo.OrgId},
                {ClaimConst.CLAINM_ORGNAME, empInfo.OrgName},
                {ClaimConst.DATA_SCOPES, dataScopes}
            });
 
            // 设置Swagger自动登录
            _httpContextAccessor.HttpContext.SigninToSwagger(accessToken);
 
            // 生成刷新Token令牌
            var refreshToken =
                JWTEncryption.GenerateRefreshToken(accessToken, App.GetOptions<RefreshTokenSettingOptions>().ExpiredTime);
 
            // 设置刷新Token令牌
            _httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken;
 
            return accessToken;
        }
 
        /// <summary>
        /// 获取当前登录用户信息
        /// </summary>
        /// <returns></returns>
        [HttpGet("getLoginUser")]
        public async Task<LoginOutput> GetLoginUserAsync()
        {
            var user = _sysUserRep.FirstOrDefault(u => u.Id == CurrentUserInfo.UserId, false);
            if (user == null)
                throw Oops.Oh(ErrorCode.D1011);
            var userId = user.Id;
 
            var httpContext = _httpContextAccessor.HttpContext;
            var loginOutput = user.Adapt<LoginOutput>();
 
            loginOutput.LastLoginTime = user.LastLoginTime = DateTimeOffset.Now;
            loginOutput.LastLoginIp = user.LastLoginIp = httpContext.GetRequestIPv4();
 
            //var ipInfo = IpTool.Search(loginOutput.LastLoginIp);
            //loginOutput.LastLoginAddress = ipInfo.Country + ipInfo.Province + ipInfo.City + "[" + ipInfo.NetworkOperator + "][" + ipInfo.Latitude + ipInfo.Longitude + "]";
 
            var client = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
            loginOutput.LastLoginBrowser = client.UA.Family + client.UA.Major;
            loginOutput.LastLoginOs = client.OS.Family + client.OS.Major;
 
            // 员工信息
            loginOutput.LoginEmpInfo = await _sysEmpService.GetEmpInfo(userId);
 
            // 角色信息
            loginOutput.Roles = await _sysRoleService.GetUserRoleList(userId);
 
            // 权限信息
            loginOutput.Permissions = await _sysMenuService.GetLoginPermissionList(userId);
 
            // 系统所有权限信息
            loginOutput.AllPermissions = await _sysMenuService.GetAllPermissionList();
 
            // 数据范围信息(机构Id集合)
            loginOutput.DataScopes = await _sysUserService.GetUserDataScopeIdList(userId);
 
            // 具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统
            loginOutput.Apps = await _sysAppService.GetLoginApps(userId);
 
            // 菜单信息
            if (loginOutput.Apps.Count > 0)
            {
                var activeApp = loginOutput.Apps.FirstOrDefault(u => u.Active == YesOrNot.Y.ToString());
                var defaultActiveAppCode = activeApp != null ? activeApp.Code : loginOutput.Apps.FirstOrDefault().Code;
                loginOutput.Menus = await _sysMenuService.GetLoginMenusAntDesign(userId, defaultActiveAppCode);
            }
 
            // 更新用户最后登录Ip和时间
            await _sysUserRep.UpdateIncludeAsync(user, new[] { nameof(SysUser.LastLoginIp), nameof(SysUser.LastLoginTime) });
 
            // 增加登录日志
            await _eventPublisher.PublishAsync(new ChannelEventSource("Create:VisLog",
                new SysLogVis
                {
                    Name = loginOutput.Name,
                    Success = YesOrNot.Y,
                    Message = "登录成功",
                    Ip = loginOutput.LastLoginIp,
                    Browser = loginOutput.LastLoginBrowser,
                    Os = loginOutput.LastLoginOs,
                    VisType = LoginType.LOGIN,
                    VisTime = loginOutput.LastLoginTime,
                    Account = loginOutput.Account
                }));
            return loginOutput;
        }
 
        /// <summary>
        /// 退出
        /// </summary>
        /// <returns></returns>
        [HttpGet("logout")]
        [AllowAnonymous]
        public async Task LogoutAsync()
        {
            var ip = _httpContextAccessor.HttpContext.GetRequestIPv4();
            _httpContextAccessor.HttpContext.SignoutToSwagger();
            //_httpContextAccessor.HttpContext.Response.Headers["access-token"] = "invalid token";
 
            // 增加退出日志
            await _eventPublisher.PublishAsync(new ChannelEventSource("Create:VisLog",
                new SysLogVis
                {
                    Name = CurrentUserInfo.Name,
                    Success = YesOrNot.Y,
                    Message = "退出成功",
                    VisType = LoginType.LOGOUT,
                    VisTime = DateTimeOffset.Now,
                    Account = CurrentUserInfo.Account,
                    Ip = ip
                }));
        }
 
        /// <summary>
        /// 获取验证码开关
        /// </summary>
        /// <returns></returns>
        [HttpGet("getCaptchaOpen")]
        [AllowAnonymous]
        public async Task<bool> GetCaptchaOpen()
        {
            return await _sysConfigService.GetCaptchaOpenFlag();
        }
 
        /// <summary>
        /// 获取验证码(默认点选模式)
        /// </summary>
        /// <returns></returns>
        [HttpPost("captcha/get")]
        [AllowAnonymous]
        [NonUnify]
        public async Task<ClickWordCaptchaResult> GetCaptcha()
        {
            // 图片大小要与前端保持一致(坐标范围)
            return await _captchaHandle.CreateCaptchaImage(_captchaHandle.RandomCode(4), 310, 155);
        }
 
        /// <summary>
        /// 校验验证码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("captcha/check")]
        [AllowAnonymous]
        [NonUnify]
        public async Task<ClickWordCaptchaResult> VerificationCode(ClickWordCaptchaInput input)
        {
            return await _captchaHandle.CheckCode(input);
        }
    }
}