如何在 web api 方法中访问在 ResourceFilter 中生成的对象
How to access object thet generated in ResourceFilter inside web api method
我有一个 Web 方法在查询字符串中有一个标记,每个方法都使用这个标记来识别请求用户。
为此,我创建了一个名为 AuthenticationFilter 的 ResourceFilter,它从请求中获取令牌并从数据库中检索用户信息,如果用户有效,它允许执行该方法,否则它会抛出 UNAUTHORIZED 异常。
我的问题是:如何访问在 AuthenticationFilter class
中检索到的用户信息
我的网站api:
@GET
@Consumes(MediaType.TEXT_PLAIN)
@Produces({MediaType.APPLICATION_JSON})
@Path("/getUserOrders")
@ResourceFilters({AuthenticationFilter.class, AllowOroginFilter.class})
public String getUserOrders(@Context UriInfo uriInfo) {
//I need to access Usr object that retrived in AuthenticationFilter
/*User Usr = AuthenticationFilter.Usr;*/
String Result = getUserOrders(Usr);
return Result;
}
资源过滤器代码:
public class AuthenticationFilter implements ResourceFilter, ContainerRequestFilter, ContainerResponseFilter {
public User usr = null;
@Override
public ContainerRequest filter(ContainerRequest containerRequest) {
usr = AuthenticationUtiity.AuthenticateRequest(containerRequest);
if(usr == null){
Response.ResponseBuilder builder = null;
String response = "{\"Success\":false, \"Message\":\"Invalid username or password\"}";
builder = Response.status(Response.Status.UNAUTHORIZED).entity(response);
throw new WebApplicationException(builder.build());
}
return containerRequest;
}
}
我在谷歌上搜索了一下,找到了一种方法可以使用 ThreadLocal 并将用户保存到 ThreadLocal 并在该线程中的任何位置获取它。
https://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/
有没有更简单的方法来做到这一点?谢谢
您可以在 ContainerRequest
上设置 SecurityContext
。然后在你的资源方法中你可以用 @Context SecurityContext
注入它。对于SecurityContext
的实现,你可以实现Principal
,想怎么细就怎么细。当您在资源方法中获得 Principal
时,只需将其转换为您的类型即可。下面是一个示例过滤器:
@Provider
public class TestFilter implements ContainerRequestFilter {
@Override
public ContainerRequest filter(ContainerRequest request) {
SecurityContext oldSec = request.getSecurityContext();
final String username = "foobar";
final String email = "email@email.com";
final User user = new User(username, email);
request.setSecurityContext(new MySecurityContext(user, oldSec.isSecure()));
return request;
}
private static class MySecurityContext implements SecurityContext {
private final boolean isSecure;
private final User user;
public MySecurityContext(User user, boolean isSecure) {
this.isSecure = isSecure;
this.user = user;
}
@Override
public Principal getUserPrincipal() {
return this.user;
}
@Override
public boolean isUserInRole(String s) {
return false;
}
@Override
public boolean isSecure() {
return this.isSecure;
}
@Override
public String getAuthenticationScheme() {
return null;
}
}
public static class User implements Principal {
private final String email;
private final String username;
public User(String username, String email) {
this.username = username;
this.email = email;
}
@Override
public String getName() {
return null;
}
public String getEmail() {
return this.email;
}
}
}
然后在资源方法中
@Path("test")
public class TestResource {
@GET
public String get(@Context SecurityContext sc) {
TestFilter.User user = (TestFilter.User) sc.getUserPrincipal();
return user.getEmail();
}
}
更新
thank you for the answer but i dont want to add extra argument to my web method
然后将其作为字段注入
@Path("test")
public class TestResource {
@Context
private SecurityContext sc;
@GET
public String get() {
TestFilter.User user = (TestFilter.User) sc.getUserPrincipal();
return user.getEmail();
}
}
我有一个 Web 方法在查询字符串中有一个标记,每个方法都使用这个标记来识别请求用户。
为此,我创建了一个名为 AuthenticationFilter 的 ResourceFilter,它从请求中获取令牌并从数据库中检索用户信息,如果用户有效,它允许执行该方法,否则它会抛出 UNAUTHORIZED 异常。
我的问题是:如何访问在 AuthenticationFilter class
中检索到的用户信息我的网站api:
@GET
@Consumes(MediaType.TEXT_PLAIN)
@Produces({MediaType.APPLICATION_JSON})
@Path("/getUserOrders")
@ResourceFilters({AuthenticationFilter.class, AllowOroginFilter.class})
public String getUserOrders(@Context UriInfo uriInfo) {
//I need to access Usr object that retrived in AuthenticationFilter
/*User Usr = AuthenticationFilter.Usr;*/
String Result = getUserOrders(Usr);
return Result;
}
资源过滤器代码:
public class AuthenticationFilter implements ResourceFilter, ContainerRequestFilter, ContainerResponseFilter {
public User usr = null;
@Override
public ContainerRequest filter(ContainerRequest containerRequest) {
usr = AuthenticationUtiity.AuthenticateRequest(containerRequest);
if(usr == null){
Response.ResponseBuilder builder = null;
String response = "{\"Success\":false, \"Message\":\"Invalid username or password\"}";
builder = Response.status(Response.Status.UNAUTHORIZED).entity(response);
throw new WebApplicationException(builder.build());
}
return containerRequest;
}
}
我在谷歌上搜索了一下,找到了一种方法可以使用 ThreadLocal 并将用户保存到 ThreadLocal 并在该线程中的任何位置获取它。
https://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/
有没有更简单的方法来做到这一点?谢谢
您可以在 ContainerRequest
上设置 SecurityContext
。然后在你的资源方法中你可以用 @Context SecurityContext
注入它。对于SecurityContext
的实现,你可以实现Principal
,想怎么细就怎么细。当您在资源方法中获得 Principal
时,只需将其转换为您的类型即可。下面是一个示例过滤器:
@Provider
public class TestFilter implements ContainerRequestFilter {
@Override
public ContainerRequest filter(ContainerRequest request) {
SecurityContext oldSec = request.getSecurityContext();
final String username = "foobar";
final String email = "email@email.com";
final User user = new User(username, email);
request.setSecurityContext(new MySecurityContext(user, oldSec.isSecure()));
return request;
}
private static class MySecurityContext implements SecurityContext {
private final boolean isSecure;
private final User user;
public MySecurityContext(User user, boolean isSecure) {
this.isSecure = isSecure;
this.user = user;
}
@Override
public Principal getUserPrincipal() {
return this.user;
}
@Override
public boolean isUserInRole(String s) {
return false;
}
@Override
public boolean isSecure() {
return this.isSecure;
}
@Override
public String getAuthenticationScheme() {
return null;
}
}
public static class User implements Principal {
private final String email;
private final String username;
public User(String username, String email) {
this.username = username;
this.email = email;
}
@Override
public String getName() {
return null;
}
public String getEmail() {
return this.email;
}
}
}
然后在资源方法中
@Path("test")
public class TestResource {
@GET
public String get(@Context SecurityContext sc) {
TestFilter.User user = (TestFilter.User) sc.getUserPrincipal();
return user.getEmail();
}
}
更新
thank you for the answer but i dont want to add extra argument to my web method
然后将其作为字段注入
@Path("test")
public class TestResource {
@Context
private SecurityContext sc;
@GET
public String get() {
TestFilter.User user = (TestFilter.User) sc.getUserPrincipal();
return user.getEmail();
}
}