当前位置: 首页 > 面试题库 >

JWT发行相同的令牌

戚修雅
2023-03-14
问题内容

我正在使用制作REST API Jersey。我正在使用java-jwthttps://github.com/auth0/java-
jwt
)进行令牌生成工作。请检查以下代码。

UserJSONInfo -REST方法类

@Path ("/user_info")
public class UserInfoJSONService 
{
    @POST
    @Path("/authenticateUser")
    @Produces(MediaType.APPLICATION_JSON)
    public Response authenticateUser(Credentials credentials)
    {
        UserInfoService service = new UserInfoService();

        try{
        UserInfo authenticateUser = service.authenticateUser(credentials.getUserName(), credentials.getPassword());
        String generateToken = service.generateToken(AuthKey.authorizationSecret);

        Authentication auth = new Authentication();
        auth.setIdUser(authenticateUser.getIduser());
        auth.setToken(generateToken);

        return Response.status(Response.Status.OK).entity(auth).build();
        //return authenticateUser;
        }
        catch(IndexOutOfBoundsException e)
        {
            throw new WebApplicationException(Response.Status.BAD_REQUEST);
        } catch (JWTCreationException ex) {
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        } catch (UnsupportedEncodingException ex) {
            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
        }
    }
}

UserInfoService- 服务层

public class UserInfoService {

    private static UserInfoDAOInterface userDAOInterface;

    public UserInfoService() {
        userDAOInterface = new UserInfoDAOImpl();
    }

    public Session getSession() {
        Session session = userDAOInterface.openCurrentSession();
        return session;
    }

    public Transaction getTransaction(Session session) {
        Transaction transaction = userDAOInterface.openTransaction(session);
        return transaction;
    }



    public UserInfo authenticateUser(String userName, String password)
    {
        return authenticate(userName, password);
    }

    private UserInfo authenticate(String userName, String password) throws IndexOutOfBoundsException
    {
        Session session = userDAOInterface.openCurrentSession();
        Transaction transaction = null;
        UserInfo user = new UserInfo();

        try {
            transaction = userDAOInterface.openTransaction(session);
            user = userDAOInterface.authenticate(userName, password, session);
            transaction.commit();
//        } catch (Exception ex) {
//            //ex.printStackTrace();
//            System.out.println("OK");
//        
        } finally {
            session.close();
        }

        return user;
    }

    public String generateToken(String secret) throws JWTCreationException, UnsupportedEncodingException
    {
        Token token = new Token();
        return token.issueTokenHMAC256(secret);
    }

}

AuthKey-仅 包含secret

public interface AuthKey {
    public static String authorizationSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <servlet>
        <servlet-name>ExampleServlet</servlet-name>
        <servlet-class>test.ExampleServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>Jersey RESTful Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>rest</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>ExampleServlet</servlet-name>
        <url-pattern>/ExampleServlet</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Jersey RESTful Application</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>    
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

我将令牌生成类维护为另一个Java项目,并将其作为库导入此处(我正在使用Netbeans)。下面是代码

package com.xyz.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.io.UnsupportedEncodingException;

/**
 *
 * @author Yohan
 */
public class Token {

    /**
     * Generate the HMAC256 Token
     * @param secret
     *          Secret to generate the token
     * @return 
     *      Token as a String
     * @throws UnsupportedEncodingException
     *      UTF-8 encoding not supported
     * @throws JWTVerificationException 
     *      Invalid Signing configuration / Couldn't convert Claims.
     */
    public String issueTokenHMAC256(String secret) throws UnsupportedEncodingException, JWTCreationException
    {

        String token="";
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            token = JWT.create()
                    .withIssuer("auth0")
                    .sign(algorithm);


        } catch (UnsupportedEncodingException exception) {
    //UTF-8 encoding not supported
            exception.printStackTrace();
        } catch (JWTCreationException exception) {
    //Invalid Signing configuration / Couldn't convert Claims.
            exception.printStackTrace();
        }

        return token;
    }


    /**
     * Validate a HMAC256 Token
     * @param token
     *          Token you need to validate
     * @param secret
     *          Secret used to generate the token
     * @return
     *          Returns `true` if token is valid.
     * @throws UnsupportedEncodingException
     *          UTF-8 encoding not supported
     * @throws JWTVerificationException 
     *          Invalid Signing configuration / Couldn't convert Claims.
     */
    public boolean validateTokenHMAC256(String token, String secret) throws UnsupportedEncodingException, JWTVerificationException
    {       
        Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                .withIssuer("auth0")
                .build(); //Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);

        return true;
    }
}

现在的问题是,每当我生成token用户登录名时,我都会得到相同的信息token。我POSTMAN用来检查REST方法,我打开了3个标签,并尝试为3个不同的用户登录。问题是我得到了相同的令牌!这是对还是错?在这种情况下,我该如何解决?


问题答案:

什么是基于令牌的身份验证方案

在基于令牌的身份验证方案中,令牌成为用户的凭据。硬凭证(例如用户名和密码)被交换为必须在每个请求中发送的令牌,然后服务器可以执行身份验证/授权。令牌可以在短时间内有效,可以被撤销,可以携带范围详细信息(令牌可以要求的内容)等。

使用令牌,您必须能够识别针对您的API的用户。因此,为所有经过身份验证的用户使用单个令牌是没有意义的。

解决您的问题

使用JWT后,您可以使用用户名声明所有权。还可以考虑为您的令牌添加一个过期日期(exp声明)。您不希望您的令牌永远有效,对吗?

对于java-jwt,请使用以下命令:

try {

    Algorithm algorithm = Algorithm.HMAC256("secret");
    Date expirationDate = Date.from(ZonedDateTime.now().plusMinutes(60).toInstant());
    String token = JWT.create()
                      .withExpiresAt(expirationDate)
                      .withClaim("username", username)
                      .sign(algorithm);

} catch (UnsupportedEncodingException e){
    // UTF-8 encoding not supported
} catch (JWTCreationException e){
    // Invalid signing configuration / Couldn't convert claims
}

验证令牌时,您将能够获得username索赔并知道谁为以下对象颁发了令牌:

try {

    Algorithm algorithm = Algorithm.HMAC256("secret");
    JWTVerifier verifier = JWT.require(algorithm).build();
    DecodedJWT jwt = verifier.verify(token);

    Claim usernameClaim = jwt.getClaim("username");
    String username = usernameClaim.asString();

} catch (UnsupportedEncodingException e){
    // UTF-8 encoding not supported
} catch (JWTVerificationException e){
    // Invalid signature/claims
}

使用JWT处理令牌刷新


接受有效(未过期)令牌进行刷新。客户有责任在exp索赔中指定的到期日期之前刷新令牌。

为了避免无限期刷新令牌,您可以通过向令牌添加两个声明(声明名称取决于您)来跟踪令牌刷新:

  • refreshLimit:指示令牌可以刷新多少次。
  • refreshCount:指示令牌已刷新多少次。

因此,仅在满足以下条件时才刷新令牌:

  • 令牌未过期(exp >= now)。
  • 令牌已刷新的次数少于令牌可刷新的次数(refreshCount < refreshLimit)。

当刷新令牌时:

  • 更新到期日期(exp = now + some-amount-of-time)。
  • 增加令牌已刷新(refreshCount++)的次数。

令牌签名并在服务器端验证签名后,客户端就无法篡改令牌的内容。

除了跟踪刷新次数之外,您还可以要求声明 绝对到期日期 。在此日期之前,可以接受任何数量的茶点。

另一种方法涉及发行单独的长期刷新令牌,该令牌用于发行短期JWT令牌。

最佳方法取决于您的要求。

使用JWT处理令牌吊销

如果要撤消令牌,则必须跟踪它们。您不需要将整个令牌存储在服务器端,只需存储令牌标识符(必须是唯一的)和一些元数据(如果需要)。对于令牌标识符,您可以使用UUID。

jti权利要求应该被用来存储在令牌本身的令牌标识符。验证令牌时,通过jti对照服务器端的令牌标识符检查索偿值,确保未撤销令牌。

为了安全起见,请在用户更改密码时撤消该用户的所有令牌。



 类似资料:
  • 我正在用制作一个rest API。我使用(https://github.com/auth0/java-jwt)进行令牌生成工作。请检查下面的代码。 UserInfoService-服务层 AuthKey-仅包含 web.xml

  • {“access_token”:“txxxxxxxxxxxxxxxxxxfb45a”,“expires_in”:36000,“token_type”:“承载”,“scope”:“读写组”,“refresh_token”:“16okxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxfb45a”} 到 {“access_token”:“xxxxxxxx.xxxxx.xxxxxx”,“e

  • 我漫不经心地阅读了英特尔架构参考手册,http://www.cs.princeton.edu/courses/archive/spr12/cos217/reading/ia32opt.pdf,当我阅读指令延迟和吞吐量附录时,我发现sqrt指令的延迟(执行核心完成所有构成指令的μops的执行所需的时钟周期数。)与除法(第C-28页)指令的延迟完全相同——至少对于某些微架构来说。数字分别是30、40和

  • 我已经在Oauth2框架中实现了JWT令牌。在实现之后,我想到的查询很少,如下所示: 1.在实现JWT之前,每当用户以相应的访问令牌作为载体访问资源服务器中的API,资源服务器就使用user-info-uriendpoint与auth服务器进行检查,如下所示 在JWT实现之后,我认为资源服务器和auth服务器之间不会发生检查调用,而是使用公钥验证JWT令牌的签名。但是,在获得JWT令牌之后,为了检

  • 我将JWT的令牌发送在头中,但客户端需要它在响应的正文中,我如何将它放入响应中: