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嗎?》),無奈大家都喜歡,那我也只能隨大流。
修改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.A程式設計客棧ddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0).AddRazorRuntimeCompwww.cppcns.comilation(); services.AddFreeSqlDbContext(); services.AddBusinessServices(); services.AddAntiforgery(o => o.SuppressXFrameOptionsHeader = true); }
修改Startup檔案的ConfigureServices方法,修改認證Scheme為JwtBearerDefaults.AuthenticationScheme,在AddJwtBearer方法內配置jwt相關配置資訊。因為前後端分離專案所以有可能api跟ui部署在不同的域qoqfTtF名下,所以開啟Cors。
// 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:sqoqfTtFtring): 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,}); const authHeaderInterceptor = (url: string,options: RequestOptionsInit) => { const authHeader = { Authorization: 'Bearer ' + getToken() }; return { url: `${url}`,options: { ...options,interceptors: true,headers: authHeader },}; }; request.interceptors.request.use(authHeaderInterceptor);
修改utils/request.ts檔案,定義一個新增Authorization頭部的攔截器,並且使用這個攔截器,這有每次請求的時候自動會帶上這個頭部,把jwt 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 http://www.cppcns.com 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(_,put }) { const response = yield call(queryUsers); yield put({ type: 'save',}); },*fetchCurrent(_,put }) { const response = { name: '管理員',userid: 'admin' }; yield put({ type: 'saveCurrentUser',
修改models/user.ts檔案,修改effects的fetchCurrent方法為直接返回response。本來fetchCurrent是會去後臺拉當前使用者資訊的,因為agileconfig的使用者就admin一個,所以我直接寫死了。
讓我們試一下登入吧:)
原始碼在這:https://github.com/kklldog/AgileConfig/tree/react_ui 🌟🌟🌟
到此這篇關於AntDesign Pro + .NET Core 實現基於JWT的登入認證的文章就介紹到這了,更多相關.NET Core 登入認證內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!