JWT:'System.String' 有三个段,但不是正确的 JWS 格式

JWT: 'System.String' has three segments but is not in proper JWS format

我有一个 idToken 字符串,它由 google 返回 - 在带有 flutter 和 firebase 的移动应用程序中使用登录:

flutter 中的代码

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:google_sign_in/google_sign_in.dart';

class Authentication {
  static GoogleSignIn googleSignIn;

  static Future<User> signInWithGoogle(BuildContext context) async {
    FirebaseAuth auth = FirebaseAuth.instance;
    User user;

    googleSignIn = GoogleSignIn();

    final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();

    if (googleSignInAccount != null) {
      final GoogleSignInAuthentication googleSignInAuthentication =
          await googleSignInAccount.authentication;

      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleSignInAuthentication.accessToken,
        idToken: googleSignInAuthentication.idToken,
      );

      try {
        final UserCredential userCredential =
            await auth.signInWithCredential(credential);

        user = userCredential.user;
      } on FirebaseAuthException catch (e) {
        if (e.code == 'account-exists-with-different-credential') {
          // handle the error here
        } else if (e.code == 'invalid-credential') {
          // handle the error here
        }
      } catch (e) {
        // handle the error here
      }
      print("Credential token: ${credential.token}");
      print("Credential provider id: ${credential.providerId}");
      print("AccessToken: ${googleSignInAuthentication.accessToken}");
      print("ID Token: ${googleSignInAuthentication.idToken}");
      print("AccessToken.length: ${googleSignInAuthentication.accessToken.length}");
      print("IdToken.length: ${googleSignInAuthentication.idToken.length}");

    }
    return user;
  }

  static Future signOut() async {
    await googleSignIn.signOut();
    FirebaseAuth.instance.signOut();
  }
}

返回 ID 令牌。

然后我使用这段代码对其进行解码:

public JwtPayload PayloadInfo(string idToken)
{
     var jwtToken = new JwtSecurityToken(idToken);
     JwtPayload payload = jwtToken.Payload;
     return payload;
}

它在控制台应用程序中运行良好,但在 .net 5 web API 中它失败并出现错误:

System.ArgumentException: IDX12739: JWT: 'System.String' has three segments but is not in proper JWS format.

我研究我的 idToken 不是 JWS 类型...我不知道如何解决这个问题。 奇怪的是,函数 PayloadInfo 在 C# 控制台应用程序中工作正常,但在网络 API 中却没有。

控制器

[HttpPost("login-google")]
[MapToApiVersion("1.0")]
public async Task<IActionResult> GoogleLoginAsync(
             [FromBody] ExternalAuthModel model)
{
    if (ModelState.IsValid)
     {
          var result = await 
               _userService.GoogleExternalLoginAsync(model);

           if (result.IsSuccess)
           {
               return Ok(result);
           }
           return BadRequest(result);
      }

    return BadRequest("Somethings going wrong...");
}

ExternalAuthModel

public class ExternalAuthModel
{
    public string Provider { get; set; }
    public string IdToken { get; set; }
}

GoogleExternalLoginAsync 函数在我的服务中

public async Task<UserManagerResponse> GoogleExternalLoginAsync(ExternalAuthModel model)
{
    var payload = _jwtHandler.PayloadInfo(model.IdToken);
    
    if (payload is null)
    {
        return new UserManagerResponse
        {
            Message = "Invalid google authentication.",
            IsSuccess = false
        };
    }

    var info = new UserLoginInfo(model.Provider, payload.Sub, model.Provider);
    var user = await _userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);

    if (user is null)
    {

        user = await _userManager.FindByEmailAsync(payload["email"].ToString());
        await _userManager.CreateAsync(user);

        if (!await _roleManager.RoleExistsAsync(UserRoles.User))
            await _roleManager.CreateAsync(new IdentityRole(UserRoles.User));

        await _userManager.AddToRoleAsync(user, UserRoles.User);
        await _userManager.AddLoginAsync(user, info);
    }
    else
    {
        await _userManager.AddLoginAsync(user, info);
    }

    if (user is null)
    {
        return new UserManagerResponse
        {
            Message = "Invalid google authentication.",
            IsSuccess = false
        };
    }

    var token = await _jwtHandler.GenerateToken(user);
    return new UserManagerResponse
    {
        Message = token[0],
        IsSuccess = true,
        ExpireDate = DateTime.Parse(token[1])
    };

}

PayloadInfo函数

public JwtPayload PayloadInfo(string idToken)
{
    // Exception when excute this line... it says my idToken is not in 
    // JWS compact format....
    var jwtToken = new JwtSecurityToken(idToken); 
    JwtPayload payload = jwtToken.Payload;
    return payload;
}

日志...

2021-07-04T16:10:30.3810628+07:00  [ERR] An unhandled exception has occurred while executing the request. (48a46595)
System.ArgumentException: IDX12739: JWT: 'System.String' has three segments but is not in proper JWS format.
   at System.IdentityModel.Tokens.Jwt.JwtSecurityToken..ctor(String jwtEncodedString)
   at FTask.AuthServices.Helpers.JwtHandler.PayloadInfo(String idToken) in D:\cn7\Project\hao\ftask\FTask.AuthServices\Helpers\JwtHandler.cs:line 83
   at FTask.AuthServices.Services.UserService.GoogleExternalLoginAsync(ExternalAuthModel model) in D:\cn7\Project\hao\ftask\FTask.AuthServices\Services\UserService.cs:line 163
   at FTask.Api.Controllers.AuthController.GoogleLoginAsync(ExternalAuthModel model) in D:\cn7\Project\hao\ftask\FTask.Api\Controllers\AuthController.cs:line 109
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

请测试一下:

       public JwtPayload GetPayload()
        {
            var token = "<your token>";
            var handler = new JwtSecurityTokenHandler();
            var tokenData = handler.ReadJwtToken(token);
            return tokenData.Payload;
        }

我在 .Net 5 Web 中测试了您的令牌 API 并得到了这个结果: