如何在 Quarkus 应用程序中检索 SecurityContext?
How to retrieve SecurityContext in a Quarkus application?
我有一个 Quarkus 应用程序,我在其中实现了 ContainerRequestFilter
接口以从传入请求中保存 header:
@PreMatching
public class SecurityFilter implements ContainerRequestFilter {
private static final String HEADER_EMAIL = "HD-Email";
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String email = requestContext.getHeaders().getFirst(HEADER_EMAIL);
if (email == null) {
throw new AuthenticationFailedException("Email header is required");
}
requestContext.setSecurityContext(new SecurityContext() {
@Override
public Principal getUserPrincipal() {
return () -> email;
}
@Override
public boolean isUserInRole(String role) {
return false;
}
@Override
public boolean isSecure() {
return false;
}
@Override
public String getAuthenticationScheme() {
return null;
}
});
}
}
在用 ApplicationScoped
注释的 class 中,我注入了如下上下文:
@ApplicationScoped
public class ProjectService {
@Context
SecurityContext context;
...
}
问题是 context
属性实际上从未被注入,因为它总是 null
。
我做错了什么?我应该怎么做才能在整个应用程序代码中检索 SecurityContext
?
@Context
只能用于 JAX-RS classes - 即 classes 注释为 @Path
.
在您的例子中,ProjectService
是 CDI bean,而不是 JAX-RS class。
做你想做的事情的规范方法是将 SecurityContext
注入 JAX-RS 资源,然后将其作为方法参数传递给你的 ProjectService
我喜欢抽象这个问题,以便业务逻辑不依赖于特定于 JAX-RS 的构造。因此,我创建了一个 class 来描述我的用户,比如 User
,以及另一个接口 AuthenticationContext
,它包含当前用户和我需要的任何其他与身份验证相关的信息,例如:
public interface AuthenticationContext {
User getCurrentUser();
}
我创建了这个 class 的 RequestScoped
实现,它也有相关的 setter(s):
@RequestScoped
public class AuthenticationContextImpl implements AuthenticationContext {
private User user;
@Override
public User getCurrentUser() {
return user;
}
public void setCurrentUser(User user) {
this.user = user;
}
}
现在,我将这个 bean 和 JAX-RS SecurityContext
注入到一个过滤器中,它知道如何创建 User
并将其设置到我的特定应用程序 AuthenticationContext
中:
@PreMatching
public class SecurityFilter implements ContainerRequestFilter {
@Inject AuthenticationContextImpl authCtx; // Injecting the implementation,
// not the interface!!!
@Context SecurityContext securityCtx;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
User user = ...// translate the securityCtx into a User
authCtx.setCurrentUser(user);
}
}
然后,任何需要用户数据的业务 bean 都会注入与环境无关、特定于应用程序的 AuthenticationContext
。
我有一个 Quarkus 应用程序,我在其中实现了 ContainerRequestFilter
接口以从传入请求中保存 header:
@PreMatching
public class SecurityFilter implements ContainerRequestFilter {
private static final String HEADER_EMAIL = "HD-Email";
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String email = requestContext.getHeaders().getFirst(HEADER_EMAIL);
if (email == null) {
throw new AuthenticationFailedException("Email header is required");
}
requestContext.setSecurityContext(new SecurityContext() {
@Override
public Principal getUserPrincipal() {
return () -> email;
}
@Override
public boolean isUserInRole(String role) {
return false;
}
@Override
public boolean isSecure() {
return false;
}
@Override
public String getAuthenticationScheme() {
return null;
}
});
}
}
在用 ApplicationScoped
注释的 class 中,我注入了如下上下文:
@ApplicationScoped
public class ProjectService {
@Context
SecurityContext context;
...
}
问题是 context
属性实际上从未被注入,因为它总是 null
。
我做错了什么?我应该怎么做才能在整个应用程序代码中检索 SecurityContext
?
@Context
只能用于 JAX-RS classes - 即 classes 注释为 @Path
.
在您的例子中,ProjectService
是 CDI bean,而不是 JAX-RS class。
做你想做的事情的规范方法是将 SecurityContext
注入 JAX-RS 资源,然后将其作为方法参数传递给你的 ProjectService
我喜欢抽象这个问题,以便业务逻辑不依赖于特定于 JAX-RS 的构造。因此,我创建了一个 class 来描述我的用户,比如 User
,以及另一个接口 AuthenticationContext
,它包含当前用户和我需要的任何其他与身份验证相关的信息,例如:
public interface AuthenticationContext {
User getCurrentUser();
}
我创建了这个 class 的 RequestScoped
实现,它也有相关的 setter(s):
@RequestScoped
public class AuthenticationContextImpl implements AuthenticationContext {
private User user;
@Override
public User getCurrentUser() {
return user;
}
public void setCurrentUser(User user) {
this.user = user;
}
}
现在,我将这个 bean 和 JAX-RS SecurityContext
注入到一个过滤器中,它知道如何创建 User
并将其设置到我的特定应用程序 AuthenticationContext
中:
@PreMatching
public class SecurityFilter implements ContainerRequestFilter {
@Inject AuthenticationContextImpl authCtx; // Injecting the implementation,
// not the interface!!!
@Context SecurityContext securityCtx;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
User user = ...// translate the securityCtx into a User
authCtx.setCurrentUser(user);
}
}
然后,任何需要用户数据的业务 bean 都会注入与环境无关、特定于应用程序的 AuthenticationContext
。