Java-JWT令牌无效签名

Java-JWT令牌无效签名,java,authentication,jwt,Java,Authentication,Jwt,我在验证JWT令牌时遇到了一个问题,尽管它给了我正确的负载 如果我对这部分代码有点不安全,请原谅,因为这是我们的老师通过模板分发的,但我们无法联系到他 我们必须对代码本身进行一些更改,因为它将用户名放入令牌中,我们希望将电子邮件放入令牌中 据我所知,我们使用的是UserPrincipal,它用于确定对文件或对象的访问权限,最初我们使用角色来确定哪些用户可以访问哪些端点。本项目并非如此,因为它是基于其他功能的简短演示 我们的用户主体类是什么样子的 package rest; import ent

我在验证JWT令牌时遇到了一个问题,尽管它给了我正确的负载

如果我对这部分代码有点不安全,请原谅,因为这是我们的老师通过模板分发的,但我们无法联系到他

我们必须对代码本身进行一些更改,因为它将用户名放入令牌中,我们希望将电子邮件放入令牌中

据我所知,我们使用的是UserPrincipal,它用于确定对文件或对象的访问权限,最初我们使用角色来确定哪些用户可以访问哪些端点。本项目并非如此,因为它是基于其他功能的简短演示

我们的用户主体类是什么样子的

package rest;

import entity.User;

import java.security.Principal;

public class UserPrincipal implements Principal {

    private String name;
    private String email;

    public UserPrincipal(User user) {
        this.email = user.getEmail();
    }

    public UserPrincipal(String email) {
        super();
        this.email = email;
    }

    @Override
    public String getName() {
        return email;
    }

}
请看,这里的用户主体还用于获取角色列表,而不是电子邮件,而是用户名

我们在哪里使用这个用户主体?嗯,我们在生成令牌时使用它。这也是我们的端点,是的,它应该被移动到我们的接口类

package rest;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import entity.User;
import facade.UserFacade;
import exceptions.AuthenticationException;
import exceptions.GenericExceptionMapper;
import utils.PuSelector;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

@Path("login")
public class LoginEndpoint {

    private static final int TOKEN_EXPIRE_TIME = 1000 * 60 * 30; // ms * sec * min = 30 min
    private static final UserFacade USER_FACADE = UserFacade.getInstance(PuSelector.getEntityManagerFactory("pu"));

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response login(String jsonString) throws AuthenticationException {

        JsonObject json = new JsonParser().parse(jsonString).getAsJsonObject();
        String email = json.get("email").getAsString();
        String password = json.get("password").getAsString();
        String ip = json.get("ip").getAsString();

        try {
            User user = USER_FACADE.getVeryfiedUser(email, password, ip);
            String code = USER_FACADE.sendCode(email);
            String token = createToken(email);

            JsonObject responseJson = new JsonObject();
            responseJson.addProperty("code", code);
            responseJson.addProperty("email", email);
            responseJson.addProperty("token", token);
            return Response.ok(new Gson().toJson(responseJson)).build();
        } catch (JOSEException | AuthenticationException ex) {
            if (ex instanceof AuthenticationException) {
                throw (AuthenticationException) ex;
            }
            Logger.getLogger(GenericExceptionMapper.class.getName()).log(Level.SEVERE, null, ex);
        }
        throw new AuthenticationException("Somthing went wrong! Please try again");
    }

    private String createToken(String email) throws JOSEException {
        //String firstNameLetter = user.getFirstName().substring(0, 1);
        //String lastNameLetter = user.getLastName().substring(0, 1);
        //int ageTimesID = user.getAge() * user.getId();
        //String name = firstNameLetter + lastNameLetter + ageTimesID;

        String issuer = "the_turtle_troopers";

        JWSSigner signer = new MACSigner(SharedSecret.getSharedKey());
        Date date = new Date();
        JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                .subject(email)
                .claim("email", email)
                .claim("allowed", true)
                .claim("issuer", issuer)
                .issueTime(date)
                .expirationTime(new Date(date.getTime() + TOKEN_EXPIRE_TIME))
                .build();
        SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
        signedJWT.sign(signer);
        return signedJWT.serialize();
    }
}
我们有一个安全上下文类。。不太确定这是否对我的问题有任何影响,但不管怎样:

package rest;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.SecurityContext;
import java.security.Principal;

public class JWTSecurityContext implements SecurityContext {

    UserPrincipal user;
    ContainerRequestContext request;

    public JWTSecurityContext(UserPrincipal user, ContainerRequestContext request) {
        this.user = user;
        this.request = request;
    }

    @Override
    public boolean isUserInRole(String role) {
        return true;
    }

    @Override
    public boolean isSecure() {
        return request.getUriInfo().getBaseUri().getScheme().equals("https");
    }

    @Override
    public Principal getUserPrincipal() {
        return user;
    }

    @Override
    public String getAuthenticationScheme() {
        return "JWT"; //Only for INFO
    }
}
最后我们有了JWTAuthenticationFilter:

package rest;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.SignedJWT;
import exceptions.AuthenticationException;

import javax.annotation.Priority;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

@Provider
@Priority(Priorities.AUTHENTICATION)
public class JWTAuthenticationFilter implements ContainerRequestFilter {

    private static final List<Class<? extends Annotation>> securityAnnotations 
            = Arrays.asList(DenyAll.class, PermitAll.class, RolesAllowed.class);
    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext request) throws IOException {
        if (isSecuredResource()) {

            String token = request.getHeaderString("x-access-token");//
            if (token == null) {
                request.abortWith(exceptions.GenericExceptionMapper.makeErrRes(token, 403));
                return;
            }
            try {
                UserPrincipal user = getUserPrincipalFromTokenIfValid(token);
                //What if the client had logged out????
                request.setSecurityContext(new JWTSecurityContext(user, request));
            } catch (AuthenticationException | ParseException | JOSEException ex) {
                Logger.getLogger(JWTAuthenticationFilter.class.getName()).log(Level.SEVERE, null, ex);
                request.abortWith(exceptions.GenericExceptionMapper.makeErrRes("Token not valid (timed out?)", 403));
            }
        }
    }

    private boolean isSecuredResource() {
        for (Class<? extends Annotation> securityClass : securityAnnotations) {
            if (resourceInfo.getResourceMethod().isAnnotationPresent(securityClass)) {
                return true;
            }
        }
        for (Class<? extends Annotation> securityClass : securityAnnotations) {
            if (resourceInfo.getResourceClass().isAnnotationPresent(securityClass)) {
                return true;
            }
        }
        return false;
    }

    private UserPrincipal getUserPrincipalFromTokenIfValid(String token) throws ParseException, JOSEException, AuthenticationException {
        SignedJWT signedJWT = SignedJWT.parse(token);
        //Is it a valid token (generated with our shared key)
        JWSVerifier verifier = new MACVerifier(SharedSecret.getSharedKey());

        if (signedJWT.verify(verifier)) {
            if (new Date().getTime() > signedJWT.getJWTClaimsSet().getExpirationTime().getTime()) {
                throw new AuthenticationException("Your Token is no longer valid");
            }
            String email = signedJWT.getJWTClaimsSet().getClaim("email").toString();

            return new UserPrincipal(email);
        } else {
            throw new JOSEException("User could not be extracted from token");
        }
    }
}
package-rest;
进口com.nimbusds.jose.JOSEException;
进口com.nimbusds.jose.JWSVerifier;
导入com.nimbusds.jose.crypto.MACVerifier;
进口com.nimbusds.jwt.SignedJWT;
导入异常。AuthenticationException;
导入javax.annotation.Priority;
导入javax.annotation.security.DenyAll;
导入javax.annotation.security.PermitAll;
允许导入javax.annotation.security.roles;
导入javax.ws.rs.Priorities;
导入javax.ws.rs.container.ContainerRequestContext;
导入javax.ws.rs.container.ContainerRequestFilter;
导入javax.ws.rs.container.ResourceInfo;
导入javax.ws.rs.core.Context;
导入javax.ws.rs.ext.Provider;
导入java.io.IOException;
导入java.lang.annotation.annotation;
导入java.text.ParseException;
导入java.util.array;
导入java.util.Date;
导入java.util.List;
导入java.util.logging.Level;
导入java.util.logging.Logger;
@提供者
@优先级(Priorities.AUTHENTICATION)
公共类JWTAuthenticationFilter实现ContainerRequestFilter{

private static final List您在右栏的“验证签名”下没有提供任何机密,那么jwt.io如何在不知道机密的情况下验证sig。越大(也越重要)这里的问题是,首先发布JWT的Java服务器是否能够验证令牌的校验和有效性。如何找到这个秘密@jps@dumbprogrammer:抱歉,您没有阅读所有的代码。令牌是由您自己的代码生成的吗?那么这就是您在签名令牌时使用的秘密。如果令牌来自否则,这个秘密可能是,嗯,一个秘密。@TimBiegeleisen我认为这是一个验证问题,因为从另一个端点上的令牌中减去电子邮件时无法获取用户数据。