JWT不会通过Blazor存储在ASP.NET Core中

时间:2018-10-07 22:06:24

标签: c# asp.net-core jwt blazor

我遵循了本教程:https://medium.com/@st.mas29/microsoft-blazor-web-api-with-jwt-authentication-part-1-f33a44abab9d

我下载了示例:https://github.com/StuwiiDev/DotnetCoreJwtAuthentication/tree/Part2

我可以看到令牌已创建,但是当我每次访问带有SampleDataController标签的Authorize时,我不知道该令牌是如何保存或应如何保存在客户端的,它会返回401。

使用Postman调用并添加令牌时,它可以正常工作。

要验证用户身份,我缺少什么? Microsoft.AspNetCore.Authentication.JwtBearer是否不处理客户端部分(存储令牌)?

3 个答案:

答案 0 :(得分:6)

  

要验证用户身份,我缺少什么? Microsoft.AspNetCore.Authentication.JwtBearer不能处理客户端部分(存储令牌)吗?

type actual_price recommended_price num_videos image_ava text_length 1 67.85 59 5 0 7 0 100.70 53 5 0 224 0 74.00 74 4 1 21 0 135.00 75 1 0 184 0 59.36 53 2 1 31 在服务器端运行,它将仅验证请求的授权标头,即JwtBearer,而不关心WebAssembly代码的运行方式。因此,您需要使用jwt accessToken发送请求。由于本教程建议您使用Authorization: Bearer your_access_token,因此将localStorageaccessToken一起存储。

由于localStorage尚未访问WebAssembly,因此我们需要一些javascript代码作为胶水。为此,请在BOM下添加一个helper.js

JwtAuthentication.Client/wwwroot/js/

并在您的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); };

中引用脚本
JwtAuthentication.Client/wwwroot/index.html

现在,让我们将javascript代码包装到C#中。创建一个新文件<body> <app>Loading...</app> <script src="js/helper.js"></script> <script src="_framework/blazor.webassembly.js"></script> </body>

Client/Services/TokenService.cs

现在我们可以将public class TokenService { public Task SaveAccessToken(string accessToken) { return JSRuntime.Current.InvokeAsync<object>("wasmHelper.saveAccessToken",accessToken); } public Task<string> GetAccessToken() { return JSRuntime.Current.InvokeAsync<string>("wasmHelper.getAccessToken"); } } 注入TokenService并使用它来保存令牌:

Login.cshtml

假设您要在@using JwtAuthentication.Client.Services // ... @page "/login" // ... @inject TokenService tokenService // ... @functions { public string Email { get; set; } = ""; public string Password { get; set; } = ""; public string Token { get; set; } = ""; /// <summary> /// response from server /// </summary> private class TokenResponse{ public string Token; } private async Task SubmitForm() { var vm = new TokenViewModel { Email = Email, Password = Password }; var response = await Http.PostJsonAsync<TokenResponse>("http://localhost:57778/api/Token", vm); await tokenService.SaveAccessToken(response.Token); } } 内发送数据

FetchData.cshtml

结果将是:

enter image description here

答案 1 :(得分:2)

以下类处理客户端上的登录过程,将JWT令牌存储在local存储中。注意:存储JWT令牌并将其传递到服务器是开发人员的责任。客户(Blazor,Angular等)不会自动为他执行此操作。

public class SignInManager
    {
        // Receive 'http' instance from DI
        private readonly HttpClient http;
        public SignInManager(HttpClient http)
        {
            this.http = http;
        }

        [Inject]
        protected LocalStorage localStorage;


        public bool IsAuthenticated()
        {
            var token = localStorage.GetItem<string>("token");

            return (token != null); 
        }

        public string getToken()
        {
            return localStorage.GetItem<string>("token");
        }

        public void Clear()
        {
            localStorage.Clear();
        }


        // model.Email, model.Password, model.RememberMe, lockoutOnFailure: false
        public async Task<bool> PasswordSignInAsync(LoginViewModel model)
        {
            SearchInProgress = true;
            NotifyStateChanged();

            var result = await http.PostJsonAsync<Object>("/api/Account", model);

            if (result)// result.Succeeded
           {
              _logger.LogInformation("User logged in.");

              // Save the JWT token in the LocalStorage
              // https://github.com/BlazorExtensions/Storage
              await localStorage.SetItem<Object>("token", result);


              // Returns true to indicate the user has been logged in and the JWT token 
              // is saved on the user browser
             return true;

           }

        }
    }

//这就是您调用Web API的方式,即向//当前用户发送JWT令牌

public async Task<IList<Profile>> GetProfiles()
        {   
            SearchInProgress = true;
            NotifyStateChanged();

            var token = signInManager.getToken();
            if (token == null) {
                throw new ArgumentNullException(nameof(AppState)); //"No token";
            }

            this.http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            // .set('Content-Type', 'application/json')
            // this.http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            Profiles = await this.http.GetJsonAsync<Profile[]>("/api/Profiles");


            SearchInProgress = false;
            NotifyStateChanged();
        } 

//您还必须在客户端上设置Startup类,如下所示:

public void ConfigureServices(IServiceCollection services)
    {
        // Add Blazor.Extensions.Storage
       // Both SessionStorage and LocalStorage are registered
       // https://github.com/BlazorExtensions/Storage
       **services.AddStorage();**

      ...
    }

//一般来说,这就是您必须在客户端上执行的操作。 //在服务器上,您必须有一个方法,例如在Account控制器中,该方法的功能是生成JWT令牌,您必须配置JWT中间件,以为控制器添加必要的属性,例如实例:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]  

以此类推...

希望这对您有帮助...

答案 2 :(得分:2)

提前道歉,因为这在某种程度上回应了先前的答案,但我没有代表对此发表评论。

如果它可以帮助其他在Blazor应用程序中寻找使用JWT的解决方案的人,我发现@itminus答案非常有用,但这也为我指明了另一门课程。

我发现的一个问题是,尝试再次添加FetchData.cshtml头时,第二次调用Authorization会崩溃。

我没有在其中添加默认标头,而是在成功登录后将其添加到HttpClient单例中(我相信Blazor会自动为您创建)。因此,请从@itminus的答案中更改SubmitForm中的Login.cshtml

    protected async Task SubmitForm()
    {
        // Remove any existing Authorization headers
        Http.DefaultRequestHeaders.Remove("Authorization");

        TokenViewModel vm = new TokenViewModel()
        {
            Email = Email,
            Password = Password
        };

        TokenResponse response = await Http.PostJsonAsync<TokenResponse>("api/Token/Login", vm);

        // Now add the token to the Http singleton
        Http.DefaultRequestHeaders.Add("Authorization", string.Format("Bearer {0} ", response.Token));
    }

然后我意识到,而不是在构建SPA时,因此我根本不需要在请求之间持久保存令牌-它只是附加在HttpClient上。