【问题标题】:How to have jersey inject a param based on the http header?如何让球衣基于 http 标头注入参数?
【发布时间】:2023-03-10 16:59:01
【问题描述】:

我有一个接口,想将其作为 REST API 打开。

界面:

string createToken(String username, String scopes);

REST 网络 API:

@GET
@Path("/createToken")
@Override
public string createToken(@InjectParam String username, String scopes) {
  ...
}

作为一个简单的 Java API,接口本身很有意义 - 由特定(唯一)用户创建访问令牌。

但是,作为 REST Web API,我需要上一步来检索用户名,基于在 http 标头中传递的一些用户数据,如 SSO 密钥。

如何将值注入到从 HTTP 标头中提取的 username 谢谢。

【问题讨论】:

标签: jersey jax-rs


【解决方案1】:

创建了一个Provider 以将值注入到自定义注释中。请参阅小型工作示例here。请参阅下面的内联源代码。

该示例从 sso 令牌中提取用户名。这是一个虚拟提取。

* 我没有使用@InjectParam

调用示例:

curl -X POST -H "ssoToken: 1234" http://localhost:8080/JerseyCustomParamInjection-1.0-SNAPSHOT/oauth2/createAccessToken

自定义注解:

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggedUser {
}

提供者进行注入:

@Provider
public class LoggedUserProvider implements
        Injectable<String>,
        InjectableProvider<LoggedUser, Parameter> {

    @Context
    private HttpServletRequest request;

    public LoggedUserProvider() {
    }

    @Override
    public Injectable<String> getInjectable(ComponentContext cc, LoggedUser a, com.sun.jersey.api.model.Parameter c) {
        return this;
    }

    @Override
    public ComponentScope getScope() {
        return ComponentScope.PerRequest;
    }

    @Override
    public String getValue() {
        String sso = request.getHeader("ssoToken");
        if (sso == null) {
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        }
        // Retreive username from soo
        String username = " <extracted username from sso="+sso+">";
        return username;
    }
}

定义要注入值的资源:

@Path("/oauth2")
public class Resource {

    @POST
    @Path("/createAccessToken")
    public String createAccessToken(
            @LoggedUser String username
    ) {
        return username + " <created access token using the logged in injected username>";
    }
}

Servlet 配置(web.xml):

<web-app id="WebApp_ID" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Restful Web Application</display-name>
    <servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>
            com.sun.jersey.spi.container.servlet.ServletContainer
        </servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>info.fastpace.jerseycustomparaminjection</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

【讨论】:

    【解决方案2】:

    您应该使用HeaderParam。见this

    @GET
    @Path("/createToken")
    @Override
    public string createToken(@HeaderParam("username") String username, String scopes) {
      ...
    }
    

    如果你必须提取用户名并注入它,你将不得不实现一个提供者:

    @Provider
    public class UsernameProvider
          extends AbstractHttpContextInjectable<Locale>
          implements InjectableProvider<Context, Type> {
    
        @Override
        public Injectable<E> getInjectable(ComponentContext compCntxt, Context cntxt, Type typ) {
            if (typ.equals(String.class)) {
                return this;
            }
            return null;
        }
    
        @Override
        public ComponentScope getScope() {
            return ComponentScope.PerRequest;
        }
    
        @Override
        public String getValue(HttpContext httpCntxt) {
            final Request rqst = httpCntxt.getRequest();
            String username = null;
            //Extract 'username' from Headers 
            return username;
        }
    }
    

    详解here

    【讨论】:

    • 用户名未通过。也不在标题中。其他一些数据在 http 标头中传递,需要上一步将该数据转换为用户名。
    • 如果我想使用第二种方案,是否需要更改接口?如何将正确的值注入正确的参数?如何防止字符串用户名和范围混用?
    • 注解是针对用户名的。它不是方法,范围不在图片中。您在方法参数中的范围与提供者中的范围不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    • 1970-01-01
    • 2014-05-25
    • 2015-04-10
    • 1970-01-01
    相关资源
    最近更新 更多