新增移动端扫码登录

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

View File

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

View File

@ -2,6 +2,8 @@
using Lazy.Captcha.Core; using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using SqlSugar;
using System.Diagnostics;
using UAParser; using UAParser;
using ZR.Admin.WebApi.Extensions; using ZR.Admin.WebApi.Extensions;
using ZR.Admin.WebApi.Filters; using ZR.Admin.WebApi.Filters;
@ -72,6 +74,15 @@ namespace ZR.Admin.WebApi.Controllers.System
return ToResponse(ResultCode.CAPTCHA_ERROR, "验证码错误"); 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)); var user = sysLoginService.Login(loginBody, RecordLogInfo(httpContextAccessor.HttpContext));
List<SysRole> roles = roleService.SelectUserRoleListByUserId(user.UserId); List<SysRole> roles = roleService.SelectUserRoleListByUserId(user.UserId);
@ -205,5 +216,81 @@ namespace ZR.Admin.WebApi.Controllers.System
} }
return ToResponse(ResultCode.CUSTOM_ERROR, "注册失败,请联系管理员"); 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.Extensions;
using Infrastructure.Attribute;
using Infrastructure.Model;
using IPTools.Core; using IPTools.Core;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using NLog; using NLog;
using ZR.Admin.WebApi.Extensions;
using ZR.Model.System; using ZR.Model.System;
using ZR.Service.System.IService; using ZR.Service.System.IService;
@ -104,9 +101,9 @@ namespace ZR.Admin.WebApi.Filters
OperLocation = ip_info.Province + " " + ip_info.City, OperLocation = ip_info.Province + " " + ip_info.City,
Method = controller + "." + action + "()", Method = controller + "." + action + "()",
//Elapsed = _stopwatch.ElapsedMilliseconds, //Elapsed = _stopwatch.ElapsedMilliseconds,
OperTime = DateTime.Now OperTime = DateTime.Now,
OperParam = HttpContextExtension.GetRequestValue(context.HttpContext, method)
}; };
HttpContextExtension.GetRequestValue(context.HttpContext, sysOperLog);
if (logAttribute != null) if (logAttribute != null)
{ {

View File

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

View File

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

View File

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

View File

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

View File

@ -109,7 +109,7 @@
"RealIpHeader": "X-Real-IP", "RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId", "ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429, "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": { "QuotaExceededResponse": {
"Content": "{{\"code\":429,\"msg\":\"访问过于频繁,请稍后重试\"}}", "Content": "{{\"code\":429,\"msg\":\"访问过于频繁,请稍后重试\"}}",
"ContentType": "application/json", "ContentType": "application/json",

View File

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Linq;
using System.Linq;
namespace ZR.Model.System.Dto 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;
using System.Linq;
using ZR.Common; using ZR.Common;
using ZR.Common.Cache;
namespace ZR.Service.System namespace ZR.Service.System
{ {
public class CacheService public class CacheService
{ {
private readonly static string CK_verifyScan = "verifyScan_";
#region #region
public static List<string> GetUserPerms(string key) public static List<string> GetUserPerms(string key)
{ {
@ -25,5 +24,40 @@ namespace ZR.Service.System
//RedisServer.Cache.Del(key); //RedisServer.Cache.Del(key);
} }
#endregion #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;
}
} }
} }