新增移动端扫码登录

This commit is contained in:
不做码农 2023-08-26 15:54:41 +08:00
parent 710966e098
commit 6533020ebc
12 changed files with 173 additions and 57 deletions

View File

@ -1,12 +1,14 @@
using Infrastructure;
using Infrastructure.Extensions;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.RegularExpressions;
using UAParser;
using ZR.Model.System;
namespace ZR.Admin.WebApi.Extensions
namespace Infrastructure.Extensions
{
/// <summary>
/// HttpContext扩展类
@ -82,7 +84,7 @@ namespace ZR.Admin.WebApi.Extensions
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static string? GetName(this HttpContext context)
public static string GetName(this HttpContext context)
{
var uid = context.User?.Identity?.Name;
@ -105,7 +107,7 @@ namespace ZR.Admin.WebApi.Extensions
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static IEnumerable<ClaimsIdentity>? GetClaims(this HttpContext context)
public static IEnumerable<ClaimsIdentity> GetClaims(this HttpContext context)
{
return context.User?.Identities;
}
@ -131,26 +133,12 @@ namespace ZR.Admin.WebApi.Extensions
return context.Request.Headers["Authorization"];
}
/// <summary>
/// 获取浏览器信息
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static ClientInfo GetClientInfo(this HttpContext context)
{
var str = context.GetUserAgent();
var uaParser = Parser.GetDefault();
ClientInfo c = uaParser.Parse(str);
return c;
}
/// <summary>
/// 获取请求Url
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static string? GetRequestUrl(this HttpContext context)
public static string GetRequestUrl(this HttpContext context)
{
return context != null ? context.Request.Path.Value : "";
}
@ -194,14 +182,27 @@ namespace ZR.Admin.WebApi.Extensions
return body;
}
/// <summary>
/// 获取浏览器信息
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static ClientInfo GetClientInfo(this HttpContext context)
{
var str = context.GetUserAgent();
var uaParser = Parser.GetDefault();
ClientInfo c = uaParser.Parse(str);
return c;
}
/// <summary>
/// 设置请求参数
/// </summary>
/// <param name="operLog"></param>
/// <param name="reqMethod"></param>
/// <param name="context"></param>
public static void GetRequestValue(this HttpContext context, SysOperLog operLog)
public static string GetRequestValue(this HttpContext context,string reqMethod)
{
string reqMethod = operLog.RequestMethod;
string param= string.Empty;
if (HttpMethods.IsPost(reqMethod) || HttpMethods.IsPut(reqMethod) || HttpMethods.IsDelete(reqMethod))
@ -213,7 +214,7 @@ namespace ZR.Admin.WebApi.Extensions
{
param = context.GetQueryString();
}
operLog.OperParam = param;
return param;
}
[GeneratedRegex("(?<=\"password\":\")[^\",]*")]

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
@ -14,6 +14,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="UAParser" Version="3.1.47" />
</ItemGroup>
</Project>

View File

@ -2,6 +2,8 @@
using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using SqlSugar;
using System.Diagnostics;
using UAParser;
using ZR.Admin.WebApi.Extensions;
using ZR.Admin.WebApi.Filters;
@ -72,6 +74,15 @@ namespace ZR.Admin.WebApi.Controllers.System
return ToResponse(ResultCode.CAPTCHA_ERROR, "验证码错误");
}
var lockTimeStamp = CacheService.GetLockUser(loginBody.ClientId);
var lockTime = DateTimeHelper.ToLocalTimeDateBySeconds(lockTimeStamp);
var ts = lockTime - DateTime.Now;
if (lockTimeStamp > 0 && ts.TotalSeconds > 0)
{
return ToResponse(ResultCode.LOGIN_ERROR, $"你的账号已被锁,剩余{Math.Round(ts.TotalMinutes, 0)}分钟");
}
var user = sysLoginService.Login(loginBody, RecordLogInfo(httpContextAccessor.HttpContext));
List<SysRole> roles = roleService.SelectUserRoleListByUserId(user.UserId);
@ -205,5 +216,81 @@ namespace ZR.Admin.WebApi.Controllers.System
}
return ToResponse(ResultCode.CUSTOM_ERROR, "注册失败,请联系管理员");
}
#region
/// <summary>
/// 生成二维码
/// </summary>
/// <param name="uuid"></param>
/// <param name="deviceId"></param>
/// <returns></returns>
[HttpGet("/GenerateQrcode")]
public IActionResult GenerateQrcode(string uuid, string deviceId)
{
var state = Guid.NewGuid().ToString();
var dict = new Dictionary<string, object>
{
{ "state", state }
};
CacheService.SetScanLogin(uuid, dict);
return SUCCESS(new
{
status = 1,
state,
uuid,
codeContent = new { uuid, deviceId }// "https://qm.qq.com/cgi-bin/qm/qr?k=kgt4HsckdljU0VM-0kxND6d_igmfuPlL&authKey=r55YUbruiKQ5iwC/folG7KLCmZ++Y4rQVgNlvLbUniUMkbk24Y9+zNuOmOnjAjRc&noverify=0"
});
}
/// <summary>
/// 轮询判断扫码状态
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("/VerifyScan")]
[AllowAnonymous]
public IActionResult VerifyScan([FromBody] ScanDto dto)
{
int status = -1;
object token = string.Empty;
if (CacheService.GetScanLogin(dto.Uuid) is Dictionary<string, object> str)
{
status = 0;
str.TryGetValue("token", out token);
if (str.ContainsKey("status") && (string)str.GetValueOrDefault("status") == "success")
{
status = 2;//扫码成功
CacheService.RemoveScanLogin(dto.Uuid);
}
}
return SUCCESS(new { status, token });
}
/// <summary>
/// 移动端扫码登录
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("/ScanLogin")]
[Log(Title = "扫码登录")]
public IActionResult ScanLogin([FromBody] ScanDto dto)
{
if (dto == null) { return ToResponse(ResultCode.CUSTOM_ERROR, "扫码失败"); }
var token = HttpContextExtension.GetToken(HttpContext);
if (CacheService.GetScanLogin(dto.Uuid) is not null)
{
Dictionary<string, object> dict = new() { };
dict.Add("status", "success");
dict.Add("token", token.Replace("Bearer ", ""));
CacheService.SetScanLogin(dto.Uuid, dict);
//TODO 待优化应该生成新的token
return SUCCESS(1);
}
return ToResponse(ResultCode.FAIL, "二维码已失效");
}
#endregion
}
}

View File

@ -1,12 +1,9 @@
using Infrastructure;
using Infrastructure.Attribute;
using Infrastructure.Model;
using Infrastructure.Extensions;
using IPTools.Core;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using NLog;
using ZR.Admin.WebApi.Extensions;
using ZR.Model.System;
using ZR.Service.System.IService;
@ -104,9 +101,9 @@ namespace ZR.Admin.WebApi.Filters
OperLocation = ip_info.Province + " " + ip_info.City,
Method = controller + "." + action + "()",
//Elapsed = _stopwatch.ElapsedMilliseconds,
OperTime = DateTime.Now
OperTime = DateTime.Now,
OperParam = HttpContextExtension.GetRequestValue(context.HttpContext, method)
};
HttpContextExtension.GetRequestValue(context.HttpContext, sysOperLog);
if (logAttribute != null)
{
@ -117,7 +114,7 @@ namespace ZR.Admin.WebApi.Filters
}
LogEventInfo ei = new(NLog.LogLevel.Info, "GlobalActionMonitor", "");
ei.Properties["jsonResult"] = !HttpMethods.IsGet(method) ? jsonResult : "";
ei.Properties["requestParam"] = sysOperLog.OperParam;
ei.Properties["user"] = userName;

View File

@ -1,13 +1,7 @@
using Infrastructure;
using Infrastructure.Model;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using NLog;
using System;
using System.Linq;
using ZR.Admin.WebApi.Extensions;
using ZR.Admin.WebApi.Framework;
using ZR.Model.System.Dto;

View File

@ -4,4 +4,5 @@ global using Infrastructure;
global using Infrastructure.Attribute;
global using Infrastructure.Enums;
global using Infrastructure.Model;
global using Mapster;
global using Mapster;
global using Infrastructure.Extensions;

View File

@ -1,14 +1,8 @@
using Infrastructure;
using Infrastructure.Attribute;
using Infrastructure.Model;
using IPTools.Core;
using IPTools.Core;
using Microsoft.AspNetCore.Http.Features;
using NLog;
using System.Diagnostics;
using System.Text.Encodings.Web;
using System.Text.Json;
using ZR.Admin.WebApi.Extensions;
using ZR.Common;
using ZR.Model.System;
using ZR.Service.System.IService;
@ -90,9 +84,9 @@ namespace ZR.Admin.WebApi.Middleware
ErrorMsg = string.IsNullOrEmpty(error) ? msg : error,
OperName = HttpContextExtension.GetName(context),
OperLocation = ip_info.Province + " " + ip_info.City,
OperTime = DateTime.Now
OperTime = DateTime.Now,
OperParam = HttpContextExtension.GetRequestValue(context, context.Request.Method)
};
HttpContextExtension.GetRequestValue(context, sysOperLog);
var endpoint = GetEndpoint(context);
if (endpoint != null)
{

View File

@ -20,7 +20,6 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.7" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.6" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="IPTools.China" Version="1.6.0" />
<PackageReference Include="NLog" Version="5.2.3" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.3" />

View File

@ -109,7 +109,7 @@
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"EndpointWhitelist": [ "post:/system/dict/data/types", "*:/msghub/negotiate", "*:/LogOut", "*:/common/uploadfile" ],
"EndpointWhitelist": [ "post:/system/dict/data/types", "*:/msghub/negotiate", "*:/LogOut", "*:/common/uploadfile", "*:/VerifyScan" ],
"QuotaExceededResponse": {
"Content": "{{\"code\":429,\"msg\":\"访问过于频繁,请稍后重试\"}}",
"ContentType": "application/json",

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq;
namespace ZR.Model.System.Dto
{

View File

@ -0,0 +1,9 @@
namespace ZR.Model.System.Dto
{
public class ScanDto
{
public string Uuid { get; set; }
public string State { get; set; }
public string DeviceId { get; set; }
}
}

View File

@ -1,12 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using System;
using ZR.Common;
using ZR.Common.Cache;
namespace ZR.Service.System
{
public class CacheService
{
private readonly static string CK_verifyScan = "verifyScan_";
#region
public static List<string> GetUserPerms(string key)
{
@ -25,5 +24,40 @@ namespace ZR.Service.System
//RedisServer.Cache.Del(key);
}
#endregion
public static object SetScanLogin(string key, Dictionary<string, object> val)
{
var ck = CK_verifyScan + key;
return CacheHelper.SetCache(ck,val , 1);
}
public static object GetScanLogin(string key)
{
var ck = CK_verifyScan + key;
return CacheHelper.Get(ck);
}
public static void RemoveScanLogin(string key)
{
var ck = CK_verifyScan + key;
CacheHelper.Remove(ck);
}
public static void SetLockUser(string key, long val, int time)
{
var CK = "lock_user_" + key;
CacheHelper.SetCache(CK, val, time);
}
public static long GetLockUser(string key)
{
var CK = "lock_user_" + key;
if (CacheHelper.Get(CK) is long t)
{
return t;
}
return 0;
}
}
}