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