在访问带有[Authorize]的方法的时候,需要前端通过自定义报文头的形式将JWT令牌传递给后端进行验证,否则是不能访问带有[Authorize]的方法。
[Authorize]是用于限制对web应用程序中某些操作或控制器的访问。当[授权]属性应用于操作或控制器时,它表示用户必须经过身份验证和授权才能访问该特定资源。还可以使用其他参数自定义此属性,以根据特定角色或策略进一步限制访问。
但是Websocket是不支持自定义报文头的,所以我们只能通过url将JWT令牌进行传递。
这里创建了一个实现SignalR的方法,该方法带有[Authorize],功能是前端传递什么返回什么。
public class Myhub : Hub
{
[Authorize]
public Task SendPublicMsg(string msg)
{
string msgToSend = msg;
return Clients.All.SendAsync("publicMsgReceived", msgToSend);
}
}
在Program.cs中的配置
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//JWT配置
builder.Services.Configure<JWTSettings>(builder.Configuration.GetSection("JWT"));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>
{
var jwtSettings = builder.Configuration.GetSection("JWT").Get<JWTSettings>();
byte[] keyBytes = Encoding.UTF8.GetBytes(jwtSettings.SecKey);
var secKey = new SymmetricSecurityKey(keyBytes);
opt.TokenValidationParameters = new()
{
ValidateIssuer=false,
ValidateAudience=false,
ValidateLifetime=true,
ValidateIssuerSigningKey=true,
IssuerSigningKey=secKey
};
opt.Events = new JwtBearerEvents
{
//Websocket不支持自定义报文头
OnMessageReceived = context =>
{
var accessToke = context.Request.Query["access_token"];//取出JWT
var path = context.Request.Path;
if (!string.IsNullOrEmpty(accessToke) && path.StartsWithSegments("/Myhub"))
{
context.Token = accessToke;
}
return Task.CompletedTask;
}
};
});
builder.Services.AddSignalR();//调用SignalR
builder.Services.AddMemoryCache();
app.UseCors();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapHub<Myhub>("/Myhub");
app.MapControllers();
app.Run();
前端
界面
<div>
<button @click="JwtItem">连接</button>
<button @click="sendMessage">发送</button>
<input type="text" v-model="sigtext"/>
<p v-for="i in msgs">{{i}}</p>
</div>
该连接要在后端返回你的JWT令牌后进行连接
startConnection() {
var options={skipNegotiation:true,transport:signalR.HttpTransportType.WebSockets};
//this.JWTkey你的JWT令牌
options.accessTokenFactory=()=>this.JWTkey;
//创建连接
this.connection = new signalR.HubConnectionBuilder()
//大括号里面强制执行Websockets通道(解决分布式问题)
.withUrl('https://localhost:44334/Myhub',options)
.withAutomaticReconnect() //断开自动连接
.build();
//注册
this.connection.on('publicMsgReceived', res=>{
this.msgs.push(res)
});
//开始连接
this.connection.start();
},
JwtItem(){
this.startConnection();//调用startConnection方法
},
//调用后端方法
sendMessage() {
//传递数据
this.connection.invoke('SendPublicMsg', this.sigtext)
}
启动连接,我们可以看到JWT令牌通过url中的QueryString传递。