如何在 Android 上从 JWT 收集签名、标头和正文

Posted

技术标签:

【中文标题】如何在 Android 上从 JWT 收集签名、标头和正文【英文标题】:How to collect the signature, header and body from JWT on Android 【发布时间】:2016-10-14 20:19:45 【问题描述】:

我最近了解了 Json Web Token (JWT)。因为我喜欢它的工作方式,所以我开始在我的项目中实施它。我的项目涉及两个应用程序进行通信。一个是安卓应用,另一个是 Laravel Web 应用。

在服务器端验证用户凭据后,移动应用程序登录。

我已将用户名和密码从移动应用程序发送到服务器,并且我已获得字符串格式的 JWT。但从那时起,我找不到收集 JWT 内容的方法。

我已经浏览了几乎所有可能显示的结果(谷歌搜索结果),但我无法获得内容、签名和标题。

我进一步了解的一种方法是使用以下代码,请注意我已删除 setSigningKey():

try 
  Claims claims = Jwts.parser().parseClaimsJwt(jwtHeaderAndClaim).getBody();
  System.out.println("ID of the claims: " + claims.getId().toString());
  catch (Exception e)
    Log.e("Exception: ", e.toString());

以上代码产生如下错误:

Exception: io.jsonwebtoken.PrematureJwtException: JWT must not be accepted before 2016-06-14T10:20:09+0300. Current time: 2016-06-14T10:19:37+0300´ 

jwtHeaderAndClaim 是仅删除签名部分后的 JWT 字符串(即:“xxxxxx.yyyyyyyy.”)。如果我把 jwtString (xxxxxxx.yyyyyyyy.ccccccc) 而不是 jwtHeaderAndClaim 会发生以下错误:

Exception: io.jsonwebtoken.UnsupportedJwtException: Signed JWSs are not supported

如果我把setSigningKey如stormpath example所示:

Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(apiKey.getSecret())).parseClaimsJwt(jwtString).getBody();. 

上面的代码不能工作有两个原因: 1.我没有图书馆 导入 javax.xml.bind.DatatypeConverter; 2. 不知道怎么拿到钥匙。

但是知道我不需要密钥,因为这次我尝试登录并收集用户信息(如名字、姓氏、电话等)和签名(令牌),以便下次发送要存储到服务器端的数据我有访问后端的令牌。

谁能帮帮我?

【问题讨论】:

【参考方案1】:

你有很多问题。我试着回答其中一些

io.jsonwebtoken.PrematureJwtException: 之前不能接受 JWT 2016-06-14T10:20:09+0300。当前时间:2016-06-14T10:19:37+0300´

您正在 JWT 中使用 nbf(不是之前)属性。不要使用它(它是可选的)或设置一个有效范围,因为设备的时钟不会同步

来自 RFC 7519

“nbf”(不是之前)声明标识 JWT 之前的时间 不得接受处理。 “nbf”声明的处理要求当前日期/时间必须晚于或等于“nbf”声明中列出的非早于日期/时间。 实施者可以提供一些小的余地,通常不超过几分钟,以解决时钟偏差。它的值必须是一个包含 NumericDate 值的数字。 此声明的使用是可选的。

签名的 JWS

异常:io.jsonwebtoken.UnsupportedJwtException:签名的 JWS 是 不支持

您想在客户端还是在服务器端验证签名密钥? 如果您使用 JWT 进行身份验证替换用户和密码,并且您在每个请求中发送令牌,则可以在服务器端验证签名。

如果您想验证应用程序上的密钥,请不要使用对称密钥,因为如果落入坏人之手,它可能是一个很大的漏洞。 See。您可以使用非对称密钥对。使用私钥在服务器中签署 JWT,并使用公钥在设备上进行验证。

    我没有库导入 javax.xml.bind.DatatypeConverter
String base64 = Base64.encodeToString(data, Base64.DEFAULT);
byte[] data = Base64.decode(base64, Base64.DEFAULT); 
    我不知道如何获得密钥。

您的密钥可能是在服务器端以这种方式生成的

 Key key = MacProvider.generateKey(SignatureAlgorithm.HS256);
 byte data[] = key.getEncoded();

以您喜欢的方式向客户提供密钥data[]。使用非对称密钥,您只需提供公钥即可。

 KeyPair keyPair = RsaProvider.generateKeyPair();
 byte data[] = keyPair.getPublic().getEncoded();

【讨论】:

以上是关于如何在 Android 上从 JWT 收集签名、标头和正文的主要内容,如果未能解决你的问题,请参考以下文章

JWT 数字签名如何保护?

在 Spring 上从资源服务器验证 JWT 令牌

如何使用在线工具手动验证 JWT 签名

如何验证或验证 JWT 签名?

如何在 dotnet core 中验证非对称签名的 JWT?

JWT 令牌签名验证 javascript