Compare commits

..

2 Commits

Author SHA1 Message Date
youngq e7ea6956ef 别处登录,删除刷新token 2024-08-13 18:24:12 +08:00
youngq 03358fc745 新增顶号后,强制下线功能
新增进房间第一个人全员看ta
2024-08-13 15:25:36 +08:00
8 changed files with 140 additions and 12 deletions

View File

@ -1,12 +1,14 @@
using Masuit.Tools;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using NetTaste;
using SqlSugar;
using System.Configuration;
using System.Security.Claims;
using WGShare.API.Controllers.Basic;
using WGShare.API.Helpers;
using WGShare.API.Hubs;
using WGShare.Domain.Constant;
using WGShare.Domain.DTOs.Login;
using WGShare.Domain.Entities;
@ -22,13 +24,19 @@ namespace WGShare.API.Controllers
private readonly ISqlSugarClient _sqlSugar;
private readonly JwtHelper _jwtHelper;
private readonly IConfiguration _configuration;
private readonly IHubContext<SessionManageHub, IMessageClient> _hubContext;
private readonly ILogger<AuthController> _logger;
public AuthController(ISqlSugarClient sqlSugar, JwtHelper jwtHelper,
IConfiguration configuration)
IConfiguration configuration,
IHubContext<SessionManageHub, IMessageClient> hubContext,
ILogger<AuthController> logger)
{
_sqlSugar = sqlSugar;
_jwtHelper = jwtHelper;
this._configuration = configuration;
this._hubContext = hubContext;
this._logger = logger;
}
/// <summary>
@ -84,13 +92,40 @@ namespace WGShare.API.Controllers
btnAutn.Add(new Claim("uname", user.UserName));
btnAutn.Add(new Claim("ssid", user.ScreenShareId));
// 获取已登录的token
var tokens = RedisHelper.Instance.Get<AccessAndRefreshToken>(RedisKeyConstant.Data.GetAccessTokenKey(user.Id));
var accessToken = _jwtHelper.CreateToken(user.Id, btnAutn);
var refreshToken = Guid.NewGuid().ToString();
RedisHelper.Instance.Set(RedisKeyConstant.Data.GetRefreshTokenKey(refreshToken), user, TimeSpan.FromDays(30).TotalSeconds.ToInt32());
using (var pipe = RedisHelper.Instance.StartPipe())
{
if (tokens != null)
{
// 删除刷新token
pipe.Del(RedisKeyConstant.Data.GetRefreshTokenKey(tokens.RefreshToken));
}
// 设置新的刷新token
pipe.Set(RedisKeyConstant.Data.GetRefreshTokenKey(refreshToken), user, TimeSpan.FromDays(7).TotalSeconds.ToInt32());
// 记录accessToken
pipe.Set(RedisKeyConstant.Data.GetAccessTokenKey(user.Id), new AccessAndRefreshToken
{
AccessToken = accessToken,
RefreshToken = refreshToken
}, _configuration["Jwt:Expires"].ToInt32());
pipe.EndPipe();
}
// 强制下线
var connectId = RedisHelper.Instance.HGet(RedisKeyConstant.SessionManage.GetOnlineUserKey(user.TenantId), user.Id);
if (!string.IsNullOrWhiteSpace(connectId))
{
_logger.LogInformation($"账号已在其他地方登录强制下线account:{user.Account} connectId:{connectId}");
await _hubContext.Clients.Client(connectId).ForceLogout("账号已在其他地方登录,您被迫下线!");
}
return Ok(new
{
perms = user.PermValue,
token = _jwtHelper.CreateToken(user.Id, btnAutn),
token = accessToken,
refresh_token = refreshToken,
roleId = user.RoleId,
userName = user.UserName,
@ -124,15 +159,25 @@ namespace WGShare.API.Controllers
btnAutn.Add(new Claim("uname", user.UserName));
btnAutn.Add(new Claim("ssid", user.ScreenShareId));
var accessToken = _jwtHelper.CreateToken(user.Id, btnAutn);
var refreshTokenNew = Guid.NewGuid().ToString();
RedisHelper.Instance.Del(RedisKeyConstant.Data.GetRefreshTokenKey(refreshToken));
RedisHelper.Instance.Set(RedisKeyConstant.Data.GetRefreshTokenKey(refreshTokenNew), user, TimeSpan.FromDays(30).TotalSeconds.ToInt32());
using (var pipe = RedisHelper.Instance.StartPipe())
{
pipe.Del(RedisKeyConstant.Data.GetRefreshTokenKey(refreshToken));
pipe.Set(RedisKeyConstant.Data.GetRefreshTokenKey(refreshTokenNew), user, TimeSpan.FromDays(7).TotalSeconds.ToInt32());
pipe.Set(RedisKeyConstant.Data.GetAccessTokenKey(user.Id), new AccessAndRefreshToken
{
AccessToken = accessToken,
RefreshToken = refreshTokenNew
}, _configuration["Jwt:Expires"].ToInt32());
pipe.EndPipe();
}
return Ok(new
{
perms = user.PermValue,
token = _jwtHelper.CreateToken(user.Id, btnAutn),
token = accessToken,
refresh_token = refreshTokenNew,
roleId = user.RoleId,
userName = user.UserName,

View File

@ -82,7 +82,6 @@ namespace WGShare.API.Controllers.Frontend
.SplitInsert(x => !x.Any())
.ToStorage().AsInsertable.ExecuteCommandAsync();
//await _sqlSugar.Insertable(entities).ExecuteCommandAsync();
RedisHelper.Instance.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, inputDTO.RoomNum), inputDTO.UserId, user);
await _hubContext.Clients.Group(inputDTO.RoomNum).ManagerRefresh(user);
@ -258,7 +257,7 @@ namespace WGShare.API.Controllers.Frontend
});
RedisHelper.Instance.HMSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), allUsers);
// 通知其他人
await _hubContext.Clients.GroupExcept(roomNum, allUsers[UId].ConnectId).OperAllMicr(enableMicr);
await _hubContext.Clients.Group(roomNum).OperAllMicr(enableMicr);
}
@ -368,7 +367,7 @@ namespace WGShare.API.Controllers.Frontend
[HttpGet("join")]
public async Task JoinChannel([FromQuery] string roomNum, [FromQuery] bool enableMicr = false, [FromQuery] bool enableCamera = false)
{
var isManager = await _sqlSugar.Queryable<RoomManager>()
var isRoomManager = await _sqlSugar.Queryable<RoomManager>()
.InnerJoin<Room>((rm, r) => r.Id == rm.RoomId)
.Where((rm, r) => r.RoomNum == roomNum && rm.UserId == UId)
.AnyAsync();
@ -384,10 +383,15 @@ namespace WGShare.API.Controllers.Frontend
ScreenShareId = ScreenShareId,
RoleId = RoleId,
RoleName = ((RoleEnums)RoleId.ToInt32()).GetDescription(),
IsRoomManager = isManager
IsRoomManager = isRoomManager
};
using (var pipe = RedisHelper.Instance.StartPipe())
{
var script = $@"local exists = redis.call('HLEN', KEYS[1])
if exists == 0 then redis.call('HSET', KEYS[2], ARGV[1], ARGV[2]) end
return exists";
pipe.Eval(script, [RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), RedisKeyConstant.SessionManage.GetChannelShowUserKey(TenantId)], roomNum, UId);
pipe.HSet(RedisKeyConstant.SessionManage.GetChannelUserKey(TenantId, roomNum), UId, userInfo.ToJsonString());
pipe.HSet(RedisKeyConstant.SessionManage.GetUserJoinChannelKey(UId), roomNum, 1);
pipe.EndPipe();

View File

@ -97,5 +97,11 @@ namespace WGShare.API.Hubs
/// <param name="user"></param>
/// <returns></returns>
Task ManagerRefresh(ChannelUserInfo user);
/// <summary>
/// 强制退出
/// </summary>
/// <returns></returns>
Task ForceLogout(string msg);
}
}

View File

@ -28,7 +28,9 @@ namespace WGShare.API
Serialize = (x) => x.ToJsonString(),
Deserialize = (x, t) => JsonConvert.DeserializeObject(x, t),
});
#if !DEBUG
ResetRedisKey();
#endif
builder.Services.Configure<FormOptions>(options =>
{
@ -43,6 +45,7 @@ namespace WGShare.API
options.Filters.Add<GlobalExceptionFilter>();
// 全局模型赋值默认值 和 统一返回格式处理
options.Filters.Add<ModelActionFilter>();
options.Filters.Add<AuthonizationFilter>();
}).AddNewtonsoftJson(options =>
{
//修改属性名称的序列化方式,首字母小写,即驼峰样式

View File

@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.SignalR;
using WGShare.API.Helpers;
using WGShare.API.Hubs;
using WGShare.Domain.Constant;
using WGShare.Domain.DTOs.Login;
using WGShare.Domain.Entities;
namespace WGShare.API.ServiceConfigs
{
public class AuthonizationFilter : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.HttpContext.User.Identity.IsAuthenticated
&& !context.HttpContext.GetEndpoint().Metadata.Any(x => x is Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute))
{
var uid = context.HttpContext.User.Claims.FirstOrDefault(x => x.Type == "uid")?.Value;
if (string.IsNullOrWhiteSpace(uid))
{
context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedObjectResult(new { message = "身份认证有误,请重新登录!" });
context.HttpContext.Response.StatusCode = 401;
return;
}
var tokens = RedisHelper.Instance.Get<AccessAndRefreshToken>(RedisKeyConstant.Data.GetAccessTokenKey(uid));
if (tokens == null)
{
context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedObjectResult(new { message = "身份失效,请重新登录!" });
context.HttpContext.Response.StatusCode = 401;
return;
}
var token = context.HttpContext.Request.Headers.Authorization.FirstOrDefault().Replace("Bearer ", "");
if (token != tokens.AccessToken)
{
context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedObjectResult(new { message = "此账号已在别处登录,您被迫下线!" });
context.HttpContext.Response.StatusCode = 401;
return;
}
}
}
}
}

View File

@ -445,6 +445,12 @@
<param name="user"></param>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.IMessageClient.ForceLogout(System.String)">
<summary>
强制退出
</summary>
<returns></returns>
</member>
<member name="M:WGShare.API.Hubs.SessionManageHub.JoinChannel(System.String,System.Boolean,System.Boolean)">
<summary>
加入频道

View File

@ -57,9 +57,16 @@ namespace WGShare.Domain.Constant
/// </summary>
/// <param name="refreshToken"></param>
/// <returns></returns>
public static string GetRefreshTokenKey(string refreshToken) => $@"data:refresh:{refreshToken}";
public static string GetRefreshTokenKey(string refreshToken) => $@"data:refresh_tk:{refreshToken}";
public static string GetScreenShareIdKey => $@"data:screen_share_id";
/// <summary>
/// 获取Accesstoken Redis Key
/// </summary>
/// <param name="uid"></param>
/// <returns></returns>
public static string GetAccessTokenKey(string uid) => $@"data:access_tk:{uid}";
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WGShare.Domain.DTOs.Login
{
public class AccessAndRefreshToken
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
}
}