微信网站如何制作软件,现货交易平台排名,常平东莞网站设计,上海到北京高铁最快2个小时在需要登录才能访问的集线器类上或者方法上添加[Authorize]。也支持角色等设置#xff0c;可以设置到Hub或者方法上。
配置好User、Role、MyDbContext、JWTSettings、IdentityHelper
Program.cs
using SignaIR的基本使用;
using Scalar.AspNetCore;
using Identity框架;
us…在需要登录才能访问的集线器类上或者方法上添加[Authorize]。也支持角色等设置可以设置到Hub或者方法上。
配置好User、Role、MyDbContext、JWTSettings、IdentityHelper
Program.cs
using SignaIR的基本使用;
using Scalar.AspNetCore;
using Identity框架;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using System.Text;var builder WebApplication.CreateBuilder(args);builder.Services.AddControllers();
builder.Services.AddOpenApi();//添加数据库上下文
builder.Services.AddDbContextMyDbContext(opt
{string connStr Environment.GetEnvironmentVariable(ConnStr);opt.UseSqlServer(connStr);
});//添加Identity服务
builder.Services.AddDataProtection();
builder.Services.AddIdentityCoreMyUser(options
{//设置密码规则不需要数字小写字母大写字母特殊字符长度为6options.Lockout.DefaultLockoutTimeSpan TimeSpan.FromSeconds(30);options.Password.RequireDigit false;options.Password.RequireLowercase false;options.Password.RequireUppercase false;options.Password.RequireNonAlphanumeric false;options.Password.RequiredLength 6;options.Tokens.PasswordResetTokenProvider TokenOptions.DefaultEmailProvider;options.Tokens.EmailConfirmationTokenProvider TokenOptions.DefaultEmailProvider;
});
var idBuilder new IdentityBuilder(typeof(MyUser), typeof(MyRole), builder.Services);
idBuilder.AddEntityFrameworkStoresMyDbContext().AddDefaultTokenProviders().AddRoleManagerRoleManagerMyRole().AddUserManagerUserManagerMyUser();//添加JWT设置
builder.Services.ConfigureJWTSettings(builder.Configuration.GetSection(JWT));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt
{var jwtOpt builder.Configuration.GetSection(JWT).GetJWTSettings();byte[] key Encoding.UTF8.GetBytes(jwtOpt.SecKey);//设置对称秘钥var secKey new SymmetricSecurityKey(key);//设置验证参数opt.TokenValidationParameters new(){ValidateIssuer false,//是否验证颁发者ValidateAudience false,//是否验证订阅者ValidateLifetime true,//是否验证生命周期ValidateIssuerSigningKey true,//是否验证签名IssuerSigningKey secKey//签名秘钥};//设置事件opt.Events new JwtBearerEvents{OnMessageReceived context {//WebSocket不支持自定义报文头所以把JWT通过url中的QueryString传递var accessToken context.Request.Query[access_token];var path context.HttpContext.Request.Path;//如果是MyHub的请求就在服务器端的OnMessageReceived中把QueryString中的JWT读出来赋值给context.Tokenif (!string.IsNullOrEmpty(accessToken) (path.StartsWithSegments(/MyHub))){context.Token accessToken;}return Task.CompletedTask;}};});
//SignalR
builder.Services.AddSignalR();
//跨域
string[] urls new[] { http://localhost:5173 };
builder.Services.AddCors(options options.AddDefaultPolicy(builder builder.WithOrigins(urls).AllowAnyMethod().AllowAnyHeader().AllowCredentials()));var app builder.Build();if (app.Environment.IsDevelopment())
{app.MapOpenApi();app.MapScalarApiReference();
}
app.UseCors();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapHubMyHub(/MyHub);
app.MapControllers();app.Run();MyHub.cs
[Authorize]
public class MyHub : Hub
{public Task SendPublicMessage(string message){var claim this.Context.User.FindFirst(ClaimTypes.Name);string connId this.Context.ConnectionId;string msgToSend ${connId}{DateTime.Now}{message}{claim.Value};return Clients.All.SendAsync(ReceivePublicMessage, msgToSend);}
}
DemoController.cs
[Route(api/[controller]/[action])]
[ApiController]
public class DemoController : ControllerBase
{private readonly UserManagerMyUser userManager;private readonly IOptionsSnapshotJWTSettings jwtSettingsOpt;public DemoController(UserManagerMyUser userManager, IOptionsSnapshotJWTSettings jwtSettingsOpt){this.userManager userManager;this.jwtSettingsOpt jwtSettingsOpt;}[HttpPost]public async TaskActionResultstring Login(LoginRequest req){//根据用户名查找用户var user await userManager.FindByNameAsync(req.UserName);if (user null){return BadRequest(用户或密码错误1);}//判断是否登录成功失败则记录失败次数if (await userManager.CheckPasswordAsync(user, req.Password)){//登录成功重置失败次数CheckAsync判断操作是否成功失败则抛出异常await userManager.ResetAccessFailedCountAsync(user).CheckAsync();await userManager.UpdateAsync(user);//身份验证声明ListClaim claims new ListClaim{new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),new Claim(ClaimTypes.Name, user.UserName),};//获取用户角色添加到声明中var roles await userManager.GetRolesAsync(user);foreach (var role in roles){claims.Add(new Claim(ClaimTypes.Role, role));}//生成JWTstring key jwtSettingsOpt.Value.SecKey;DateTime expires DateTime.Now.AddSeconds(jwtSettingsOpt.Value.ExpireSeconds);byte[] keyBytes Encoding.UTF8.GetBytes(key);var secKey new SymmetricSecurityKey(keyBytes);var credentials new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);var tokenDescriptor new JwtSecurityToken(claims: claims,//声明expires: expires,//过期时间signingCredentials: credentials//签名凭据);string jwt new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);return jwt;}else{await userManager.AccessFailedAsync(user).CheckAsync();return BadRequest(用户或密码错误2);}}
}
Vue
templateinput typetext v-modelstate.userMessage v-on:keypresstxtMsgOnkeypress /div用户名input typetext v-modelstate.loginData.username /密码input typepassword v-modelstate.loginData.password /button v-on:clickloginClick登录/button/divdivulli v-for(msg, index) in state.messages :keyindex{{ msg }}/li/ul/div
/templatescript
import { reactive } from vue;
import * as signalR from microsoft/signalr;
import axios from axios;let connection;
export default {name: Login,setup() {//创建响应式对象const state reactive({accessToken: , userMessage: , messages: [],loginData: { userName: , password: }});//SignalR连接const startConn async function () {const transport signalR.HttpTransportType.WebSockets;const options { skipNegotiation: true, transport: transport };options.accessTokenFactory () state.accessToken;connection new signalR.HubConnectionBuilder().withUrl(https://localhost:7181/MyHub, options).withAutomaticReconnect().build();try {await connection.start();} catch (err) {alert(err);return;}//注册ReceivePublicMessage事件接收消息添加到messages数组connection.on(ReceivePublicMessage, msg {//监听服务器端发送过来的信息state.messages.push(msg);});}//点击登录const loginClick async function () {const resp await axios.post(https://localhost:7181/api/Demo/Login, state.loginData).then((response) {state.accessToken response.data;startConn()})};//按下回车键发送消息调用SendPublicMessage方法发送消息清空输入框const txtMsgOnkeypress async function (e) {if (e.keyCode ! 13) return;await connection.invoke(SendPublicMessage, state.userMessage); state.userMessage ;};//返回响应式对象和方法return { state, txtMsgOnkeypress, loginClick };},
}
/script