我试图在tomee8中实现基于jwt的身份验证(基于tomcat9)。我用org.glassfish。soteria:jakarta.security.enterprise:1.0.1作为雅加达安全的一个实现。遵循本教程https://github.com/payara/payara-examples/blob/master/javaee/security-jwt-example/src/main/java/fish/payara/examples/security/jwtauthenticationmechanism.java java类如下所示:
@RequestScoped
public class JWTAuthenticationMechanism implements HttpAuthenticationMechanism
private static final Logger LOGGER = Logger.getLogger(JWTAuthenticationMechanism.class.getName());
/**
* Access to the
* IdentityStore(AuthenticationIdentityStore,AuthorizationIdentityStore) is
* abstracted by the IdentityStoreHandler to allow for multiple identity
* stores to logically act as a single IdentityStore
*/
@Inject
private IdentityStoreHandler identityStoreHandler;
@Inject
private TokenProvider tokenProvider;
@Override
public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext context) {
LOGGER.log(Level.INFO, "validateRequest: {0}", request.getRequestURI());
// Get the (caller) name and password from the request
// NOTE: This is for the smallest possible example only. In practice
// putting the password in a request query parameter is highly insecure
String name = request.getParameter("name");
String password = request.getParameter("password");
String token = extractToken(context);
if (name != null && password != null) {
LOGGER.log(Level.INFO, "credentials : {0}, {1}", new String[]{name, password});
// validation of the credential using the identity store
CredentialValidationResult result = identityStoreHandler.validate(new UsernamePasswordCredential(name, password));
if (result.getStatus() == CredentialValidationResult.Status.VALID) {
// Communicate the details of the authenticated user to the container and return SUCCESS.
return createToken(result, context);
}
// if the authentication failed, we return the unauthorized status in the http response
return context.responseUnauthorized();
} else if (token != null) {
// validation of the jwt credential
return validateToken(token, context);
} else if (context.isProtected()) {
// A protected resource is a resource for which a constraint has been defined.
// if there are no credentials and the resource is protected, we response with unauthorized status
return context.responseUnauthorized();
}
// there are no credentials AND the resource is not protected,
// SO Instructs the container to "do nothing"
return context.doNothing();
}
...
用户发送带有用户名和密码的登录请求,identitystorehandler验证它。然后我们生成jwt令牌并将其发送回去。前端将它附加到下一个请求。
这很管用。
validaterequest()为每个请求触发,无论是受保护的还是未受保护的。据我所知,它来自规范,是一个理想的行为。
现在,如果令牌过期,并且用户将请求发送到不受保护的url,它将被拒绝,因为令牌存在并且无效。
我想首先检查url是否受保护,并且仅当它受保护时才检查令牌的存在性和有效性。但是((httpmessagecontext)context.isprotected())总是返回false。在控制器中,受保护的方法使用@rolesallowed和@permitall注解进行注解。我也尝试了基于web.xml的约束,但是isprotected()仍然是错误的。
为什么总是假的?
更新
我错误地认为基于注解的安全性和via描述符(web.xml)是可以互换的。如果web.xml不包含任何安全约束-未经身份验证的用户对@rolesallowed资源的请求将被拒绝,并出现403错误,则对@permitall资源的请求将得到满足。这是一种奇怪的行为,既需要经过身份验证的用户,也应该被拒绝。
如果web.xml有auth constraint标记,那么context.isprotected()为该url模式返回true。
但对于带有@rolesallowed和@permitall注解的方法,如果这些方法中的路径与web.xml中的url模式不匹配,它仍然返回false。
根据这个https://www.ibm.com/support/knowledgecenter/sseqtp_8.5.5/com.ibm.websphere.base.doc/ae/twbs_jaxrs_impl_securejaxrs_annotations.html
带注解的约束是任何配置的安全约束之外的附加约束。在web容器运行时环境检查web.xml文件中配置的安全约束之后,jax-rs运行时环境检查带注解的约束。
这是否意味着基于容器的安全性(soteria)不会将带注解的方法视为受保护的方法?
暂无答案!
目前还没有任何答案,快来回答吧!