zoukankan      html  css  js  c++  java
  • 从零开始一起学Blazor WebAssembly 开发(4)

    登录模块基本完成了,登录主要用了以下几个点:

    1、后端采用的Abp Vnext 框架,这个框架自带的IdentityServer4用户角色权限控制,这个框架登录研究了好一阵子,有几个坑这里说下:

    1)、Login.Razor利用HttpClient把用户名和Rsa加密后的密码提交到后端,后端把密码解密后再往IdentityServer4的服务器获取Token(用的oauth2.0 里的密码模式),这块知识网上能搜到不少,重点说一下这里有个坑,就是我之前不知道的,传scope时,要传 offline_access 这个 才能返回RefreshToken,因为IdentityServer4 默认提供的是JWT令牌,这个令牌相关的资料也能从网上搜到不少,这里就不讲了。这个令牌有个缺点,就是服务器控制不了退出,解决办法就是让accesstoken有效时间变短,快到期时用refreshtoken 刷新,这个refreshtoken 我建议是保存在后端,不要往前端放,需要刷新时,前端传请求过来。如果必须要放在前端,IdentityServer4 提供了OneTimeOnly这种设置。就是只能用一次就换的。

    2)、IdentityServer4在每次请求之前框架有一个调用发现文档的服务(httpClient.GetDiscoveryDocumentAsync)。这个服务就是返回IdentityServer4所支持的服务,研究了下Abp vnext框架自带的,发现每次都调用这块太耗时间。就想把结果放在缓存里,结果试了很久,发现Abp自带的缓存框架处理不好这个,自己另外写也不是不行。但是就感觉不太好。然后研究发现,其实IdentityServer4 也带了一个发现文档缓存的方法IDiscoveryCache,用这个就能实现了,具体使用方法这里讲一下,因为我发现网上这个资料真不多:

    a 先注入

     //发现文档缓存
                context.Services.AddSingleton<IDiscoveryCache>(r =>
                {
                    var factory = r.GetRequiredService<IHttpClientFactory>();
                    //var policy = new DiscoveryPolicy() { },用到可以加下
                    var dc = new DiscoveryCache(configuration["IdentityClients:Default:Authority"], () => factory.CreateClient());
                    //dc.CacheDuration = TimeSpan.FromMinutes(2); 缓存有效期,    默认是24小时,需要改的话自己改
                    return dc;
                });

    b 使用

     private readonly IDiscoveryCache _ddrcache;  
              //上下两处代码结合自己的项目的Service,自己分别写。
               var disco = await _ddrcache.GetAsync();
                if (disco.IsError)
                {
                    throw new Exception(disco.Error);
                }
                return disco;

    3)、前端和后端不是在同一个域里边,原本以为webAssembly 有点近似客户端,应该不会有这个问题。发现还真的有,这就需要在后端设置下跨域设置,否则提交不了。

    2、登录后前端得到Token,要把Token信息保存到localstore里,这里用到了网上一个大神的解决方案,直接看代码

     public class TokenUtil
        {
            private readonly IJSRuntime _jsRuntime;
            public TokenUtil(IJSRuntime jsRuntime)
            {
                _jsRuntime = jsRuntime;
            }
            public async Task SaveAccessToken(string accessToken)
            {
                await _jsRuntime.InvokeVoidAsync("wasmHelper.saveAccessToken", accessToken);
            }
            public async Task<String> GetAccessToken()
            {
                return await _jsRuntime.InvokeAsync<String>("wasmHelper.getAccessToken");
            }
            public async Task RefreshToken(string tokenValue)
            {
                var httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + tokenValue);
                await httpClient.GetFromJsonAsync<TokenInfo>("");
            }
        }
    var wasmHelper = {};
    
    wasmHelper.ACCESS_TOKEN_KEY = "__access_token__";
    
    wasmHelper.saveAccessToken = function (tokenStr) {
        localStorage.setItem(wasmHelper.ACCESS_TOKEN_KEY, tokenStr);
    };
    
    wasmHelper.getAccessToken = function () {
        return localStorage.getItem(wasmHelper.ACCESS_TOKEN_KEY);
    };

    登录模块完成了,剩下就是些细节了。没有什么技术难题。

  • 相关阅读:
    C++结构体内重载、this指针和友元函数(初步了解)
    数据结构—造树计划—二叉搜索树
    PTA顺序的分数
    PTA兼容任务
    PTA航船
    UML-基于GRASP对象设计步骤
    UML-设计对象时涉及的制品有哪些?
    UML-什么是用例实现(场景实现)?
    UML-如何使用GRASP进行对象设计?
    日志总结
  • 原文地址:https://www.cnblogs.com/wcoolly/p/13286939.html
Copyright © 2011-2022 走看看