AntDesign Pro + .NET Core 实现基于JWT的登录认证
很多同学说AgileConfig的UI实在是太丑了。我想想也是的,本来这个项目是我自己使用的,一开始甚至连UI都没有,全靠手动在数据库里修改数据。后来加上了UI也是使用了老掉牙的bootstrap3做为基础样式。前台框架也是使用了angularjs,同样是老掉牙的东西。过年期间终于下决心翻新AgileConfig的前端UI。最后选择的前端UI框架为AntDesign Pro + React。至于为啥选Ant-Design Pro是因为他好看,而且流行,选择React是因为VUE跟Angular我都略知一二,干脆趁此机会学一学React为何物,为何这么流行。
登录的认证方案为JWT,其实本人对JWT不太感冒(请看这里《我们真的需要jwt吗?》),无奈大家都喜欢,那我也只能随大流。
其实基于ant-design pro的界面我已经翻的差不多了,因为它支持mock数据,所以我一行后台代码都没修改,已经把界面快些完了。从现在开始要真正的跟后端代码进行联调了。那么我们先从登录开始吧。先看看后端asp.net core方面会如何进行修改。
修改ASP.NET Core后端代码
"JwtSetting": {
"SecurityKey": "xxxxxxxxxxxx", // 密钥
"Issuer": "agileconfig.admin", // 颁发者
"Audience": "agileconfig.admin", // 接收者
"ExpireSeconds": 20 // 过期时间 s
}
在appsettings.json文件添加jwt相关配置。
public class JwtSetting
{
static JwtSetting()
{
Instance = new JwtSetting();
Instance.Audience = Global.Config["JwtSetting:Audience"];
Instance.SecurityKey = Global.Config["JwtSetting:SecurityKey"];
Instance.Issuer = Global.Config["JwtSetting:Issuer"];
Instance.ExpireSeconds = int.Parse(Global.Config["JwtSetting:ExpireSeconds"]);
}
public string SecurityKey { get; set; }
public string Issuer { get; set; }
public string Audience { get; set; }
public int ExpireSeconds { get; set; }
public static JwtSetting Instance
{
get;
}
}
定义一个JwtSetting类,用来读取配置。
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = JwtSetting.Instance.Issuer,
ValidAudience = JwtSetting.Instance.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSetting.Instance.SecurityKey)),
};
});
services.AddCors();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0).AddRazorRuntimeCompilation();
services.AddFreeSqlDbContext();
services.AddBusinessServices();
services.AddAntiforgery(o => o.SuppressXFrameOptionsHeader = true);
}
修改Startup文件的ConfigureServices方法,修改认证Scheme为JwtBearerDefaults.AuthenticationScheme,在AddJwtBearer方法内配置jwt相关配置信息。因为前后端分离项目所以有可能api跟ui部署在不同的域名下,所以开启Core。
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseMiddleware<ExceptionHandlerMiddleware>();
}
app.UseCors(op=> {
op.AllowAnyOrigin();
op.AllowAnyMethod();
op.AllowAnyHeader();
});
app.UseWebSockets(new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(60),
ReceiveBufferSize = 2 * 1024
});
app.UseMiddleware<WebsocketHandlerMiddleware>();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
修改Startup的Configure方法,配置Cors为Any。
public class JWT
{
public static string GetToken()
{
//创建用户身份标识,可按需要添加更多信息
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("id", "admin", ClaimValueTypes.String), // 用户id
new Claim("name", "admin"), // 用户名
new Claim("admin", true.ToString() ,ClaimValueTypes.Boolean) // 是否是管理员
};
var key = Encoding.UTF8.GetBytes(JwtSetting.Instance.SecurityKey);
//创建令牌
var token = new JwtSecurityToken(
issuer: JwtSetting.Instance.Issuer,
audience: JwtSetting.Instance.Audience,
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddSeconds(JwtSetting.Instance.ExpireSeconds)
);
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
return jwtToken;
}
}
添加一个JWT静态类用来生成jwt的token。因为agileconfig的用户只有admin一个所以这里用户名,ID都直接写死。
[HttpPost("admin/jwt/login")]
public async Task<IActionResult> Login4AntdPro([FromBody] LoginVM model)
{
string password = model.password;
if (string.IsNullOrEmpty(password))
{
return Json(new
{
status = "error",
message = "密码不能为空"
});
}
var result = await _settingService.ValidateAdminPassword(password);
if (result)
{
var jwt = JWT.GetToken();
return Json(new {
status="ok",
token=jwt,
type= "Bearer",
currentAuthority = "admin"
});
}
return Json(new
{
status = "error",
message = "密码错误"
});
}
新增一个Action方法做为登录的入口。在这里验证完密码后生成token,并且返回到前端。
到这里.net core这边后端代码改动的差不多了。主要是添加jwt相关的东西,这些内容网上已经写了很多了,不在赘述。
下面开始修改前端代码。
修改AntDesign Pro的代码
AntDesign Pro已经为我们生成好了登录页面,登录的逻辑等,但是原来的登录是假的,也不支持jwt token做为登录凭证,下面我们要修改多个文件来完善这个登录。
export function setToken(token:string): void {
localStorage.setItem('token', token);
}
export function getToken(): string {
var tk = localStorage.getItem('token');
if (tk) {
return tk as string;
}
return '';
}
在utils/authority.ts文件内新增2个方法,用来存储跟获取token。我们的jwt token存储在localStorage里。
/** 配置request请求时的默认参数 */
const request = extend({
prefix: 'http://localhost:5000',
errorHandler, // 默认错误处理
credentials: 'same-origin', // 默认请求是否带上cookie,
headers: {
Authorization: 'Bearer '+getToken(),
},
});
修改utils/request.ts文件,在extend方法内添加jwt认证的头部Authorization为我们的token。
设置prefix为http://localhost:5000这是我们的后端api的服务地址,真正生产的时候会替换为正式地址。
设置credentials为same-origin。
export async function accountLogin(params: LoginParamsType) {
return request('/admin/jwt/login', {
method: 'POST',
data: params,
});
}
在services/login.ts文件内新增发起登录请求的方法。
effects: {
*login({ payload }, { call, put }) {
const response = yield call(accountLogin, payload);
yield put({
type: 'changeLoginStatus',
payload: response,
});
// Login successfully
if (response.status === 'ok') {
const urlParams = new URL(window.location.href);
const params = getPageQuery();
message.success(' 登录成功!');
let { redirect } = params as { redirect: string };
if (redirect) {
console.log('redirect url ' , redirect);
const redirectUrlParams = new URL(redirect);
if (redirectUrlParams.origin === urlParams.origin) {
redirect = redirect.substr(urlParams.origin.length);
if (redirect.match(/^\/.*#/)) {
redirect = redirect.substr(redirect.indexOf('#') + 1);
}
} else {
window.location.href = '/';
return;
}
}
history.replace(redirect || '/');
}
},
reducers: {
changeLoginStatus(state, { payload }) {
setAuthority(payload.currentAuthority);
setToken(payload.token)
return {
...state,
status: payload.status,
type: payload.type,
};
},
},
修改models/login.ts文件,修改effects的login方法,在内部替换原来的fakeAccountLogin为accountLogin。同时修改reducers内部的changeLoginStatus方法,添加setToken的代码,这有修改后登录成功后token就会被存储起来。
effects: {
*fetch(_, { call, put }) {
const response = yield call(queryUsers);
yield put({
type: 'save',
payload: response,
});
},
*fetchCurrent(_, { call, put }) {
const response = {
name: '管理员',
userid: 'admin'
};
yield put({
type: 'saveCurrentUser',
payload: response,
});
},
},
修改models/user.ts文件,修改effects的fetchCurrent方法为直接返回response。本来fetchCurrent是会去后台拉当前用户信息的,因为agileconfig的用户就admin一个,所以我直接写死了。

让我们试一下登录吧:)
源码在这:https://github.com/kklldog/AgileConfig/tree/react_ui
关注我的公众号一起玩转技术

AntDesign Pro + .NET Core 实现基于JWT的登录认证的更多相关文章
- .net core 2.1 基于Jwt的登录认证
1.新建一个.net core2.1 基于 api 的工程,引用Microsoft.AspNetCore.Authentication.JwtBearer 包 2.新建一个Token的实体类,一个Jw ...
- ASP.NET Core WebApi基于JWT实现接口授权验证
一.ASP.Net Core WebApi JWT课程前言 我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再 ...
- token 与 基于JWT的Token认证
支持跨域访问,无状态认证 token特点 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输 无状态(也称:服务端可扩展行): ...
- 基于JWT的Token认证机制及安全问题
[干货分享]基于JWT的Token认证机制及安全问题 https://bbs.huaweicloud.com/blogs/06607ea7b53211e7b8317ca23e93a891
- 厉害!我带的实习生仅用四步就整合好SpringSecurity+JWT实现登录认证!
小二是新来的实习生,作为技术 leader,我还是很负责任的,有什么锅都想甩给他,啊,不,一不小心怎么把心里话全说出来了呢?重来! 小二是新来的实习生,作为技术 leader,我还是很负责任的,有什么 ...
- 简单说说基于JWT的token认证方式
一.什么是认证 好多人不知道什么是认证,认证,其实就是服务端确认用户身份.Http协议是无状态的,客户端发送一条请求,服务端返回一条响应,二者就算做成一单买卖,一拍两散.在很久以前,互联网所能提供的服 ...
- 【项目实践】一文带你搞定Session和JWT的登录认证方式
以项目驱动学习,以实践检验真知 前言 登录认证,估计是所有系统中最常见的功能了,并且也是最基础.最重要的功能.为了做好这一块而诞生了许多安全框架,比如最常见的Shiro.Spring Security ...
- JWT实现登录认证实例
JWT全称JSON Web Token,是一个紧凑的,自包含的,安全的信息交换协议.JWT有很多方面的应用,例如权限认证,信息交换等.本文将简单介绍JWT登录权限认证的一个实例操作. JWT组成 JW ...
- iOS 开发之基于JWT的Token认证机制及解析
在移动端和服务端通信中,一般有两种认证方式:token 和 session. 1.session/cookie 认证机制: 在服务端创建一个Session对象,同时在客户端的浏览器端创建一个Cooki ...
随机推荐
- Educational Codeforces Round 87 (Rated for Div. 2) D树状数组加二分删除的值
Sample Input 5 4 1 2 3 4 5 -5 -1 -3 -1 Sample Output 3 思路,首先发现a[i]的值的范围是在1~n之间,每次插入我们可以直接把cnt[a[i]]+ ...
- 2020 ICPC Asia Taipei-Hsinchu Regional Problem H Optimization for UltraNet (二分,最小生成树,dsu计数)
题意:给你一张图,要你去边,使其成为一个边数为\(n-1\)的树,同时要求树的最小边权最大,如果最小边权最大的情况有多种,那么要求总边权最小.求生成树后的所有简单路径上的最小边权和. 题解:刚开始想写 ...
- C# 之 dynamic
C#中的dynamic用于避免编译时类型检查,编译器在运行时获取类型. dynamic无法使用VisualStudio的intelliSense(智能感知),即调用dynamic修饰的对象的方法或字段 ...
- log4net GetLogger(source).IsInfoEnabled = false
GetLogger(source).IsInfoEnabled = false解决办法 在.net core中需要把log4net.config放到 ITCP.Web\ITCP.Web\obj\Rel ...
- vs2017创建文件模板(自动添加创建信息:创建者,创建日期等信息)
很多小伙伴在创建新的类的时候都要都要手动写类的注释,如作者名称.创建日期.版本等等,当有几个类的时候还可以手动写写,但有几十个或者更多的类的时候就麻烦了,所以我们可以设定Visual Studio 2 ...
- 4.Direct交换机之使用指定routingkey完成日志记录场景
标题 : 4.Direct交换机之使用指定routingkey完成日志记录场景 目录 : RabbitMQ 序号 : 4 const string logOthersQueueName = " ...
- virtualBox 设置增强功能粘贴和拖放
virtualBox 5.2.8 (在运行的虚拟里中) 设备 -> 安装增强功能 virtualBox 管理器中设置(要在虚拟机关机的情况下配置) 常规 -> 高级里设置双向粘贴和拖放
- linux下新建用户
新建用户的两种方式: 一步步创建 useradd -m user1 #-m 是建立家目录 passwd user1 #设置密码 usermod -a -G root user1 #加入管理员 chsh ...
- ARM cache 工作方式
综述 现在的CPU的速度远远高于现代存储器的速度所以出现了cache.按和CPU距离分为L1级和L2级(SM)等.这里主要记录一下自己对cache的工作方式的学习理解. cache工作方式 cahe是 ...
- 2020 Web 全栈面经
2020 Web 全栈面经 1.简历 2. 技术 3. 项目 4. 架构 5. 沟通,协作 6.成长 7. 面试技巧 准备 电话确认,面试流程,五险一金缴纳情况 有无笔试,几轮,面试时间,答复时间 细 ...