【问题标题】:ApplicationScope class created new instance every time Jersey 2.0每次 Jersey 2.0 时,ApplicationScope 类都会创建新实例
【发布时间】:2018-06-25 22:47:53
【问题描述】:

我刚刚开始学习 oAuth2 授权来保护我的 API。而且过程相当复杂。我的 API 是使用 Jersey 开发的,Apache Oltu 作为 oAuth2 授权。现在,可以生成令牌,但是,每次我尝试生成新令牌时,服务器都会创建一个 @ApplicationScoped bean 的新实例。 这是我从网上得到的 bean 代码:

@ApplicationScoped
public class Database {

private Set<String> authCodes = new HashSet<>();
private Set<String> tokens = new HashSet<>();

public void addAuthCode(String authCode) {
    authCodes.add(authCode);
}

public boolean isValidAuthCode(String authCode) {
    return authCodes.contains(authCode);
}

public void addToken(String token) {
    tokens.add(token);
}

public boolean isValidToken(String token) {
    return tokens.contains(token);
}
}

这是授权码:

@Path("/authz")
public class AuthzEndpoint {

@Inject
Database database;

@GET
public Response authorize(@Context HttpServletRequest request)
        throws URISyntaxException, OAuthSystemException {
    try {
        OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);
        OAuthIssuerImpl oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());

        //build response according to response_type
        String responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);

        OAuthASResponse.OAuthAuthorizationResponseBuilder builder =
                OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);

        if (responseType.equals(ResponseType.CODE.toString())) {
            final String authorizationCode = oauthIssuerImpl.authorizationCode();
            database.addAuthCode(authorizationCode);
            builder.setCode(authorizationCode);
        }
        if (responseType.equals(ResponseType.TOKEN.toString())) {
            final String accessToken = oauthIssuerImpl.accessToken();
            database.addToken(accessToken);

            builder.setAccessToken(accessToken);
            builder.setExpiresIn(3600l);
        }

        String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
        final OAuthResponse response = builder.location(redirectURI).buildQueryMessage();
        URI url = new URI(response.getLocationUri());
        return Response.status(response.getResponseStatus()).location(url).build();
    } catch (OAuthProblemException e) {
        final Response.ResponseBuilder responseBuilder = Response.status(HttpServletResponse.SC_FOUND);
        String redirectUri = e.getRedirectUri();

        if (OAuthUtils.isEmpty(redirectUri)) {
            throw new WebApplicationException(
                    responseBuilder.entity("OAuth callback url needs to be provided by client!!!").build());
        }
        final OAuthResponse response =
                OAuthASResponse.errorResponse(HttpServletResponse.SC_FOUND)
                        .error(e).location(redirectUri).buildQueryMessage();
        final URI location = new URI(response.getLocationUri());
        return responseBuilder.location(location).build();
    }
}
}

如您所见,那里有数据库的@Inject 注解,并在某些代码中调用了 addToken() 方法。当我尝试从我的主要 Web 服务验证令牌时,数据库 bean 为空。这是代码

@Inject
Database database;

@POST
@Path("validateLogin")
@Consumes("application/x-www-form-urlencoded")
@Produces({"application/xml", "application/json", "text/plain", "text/html"})
public Response validateLogin(@HeaderParam("Authorization") String token, @FormParam("username") String username, @FormParam("password") String password) {

    System.out.println(token.substring(7,token.length()));
    System.out.println(database.isValidToken(token.substring(7, token.length())));
    System.out.println(database);

    if (!database.isValidToken(token.substring(7, token.length()))) {
        return Response.status(Response.Status.UNAUTHORIZED).build();
    }
    else {
        String result;
        if (username == null || password == null) {
            return Response.status(Response.Status.BAD_REQUEST).build();
        }
        else {
            STCWebService stcWebService = new STCWebService();
            result = stcWebService.validateLogin(username,password);
            if (result.isEmpty()) {
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
            }
            else {
                return Response
                        .status(200)
                        .entity(result)
                        .type(MediaType.APPLICATION_JSON)
                        .header("Access-Control-Allow-Origin", "*")
                        .header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
                        .build();
            }
        }
    }
}

我一直认为 web.xml 文件或 ResourceConfig.java 甚至 ApplicationBinder 中可能存在一些错误。我已经偶然发现了这个问题几个小时。任何帮助表示赞赏。

编辑

这是 ApplicationBinder 代码

public class MyApplicationBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(Database.class).to(Database.class);
    }
}

并链接到此 MyApplication

public class MyApplication extends ResourceConfig {
    public MyApplication() {
        register(new MyApplicationBinder());
        packages("com.package");
    }
}

我根据这个问题Dependency injection with Jersey 2.0创建了ApplicationBinder和MyApplication代码

【问题讨论】:

  • 你能显示这个ApplicationBinder吗?这是你的AbstractBinder吗?
  • 是的,ApplicationBinder 就是 AbstractBinder。

标签: java spring servlets oauth-2.0 jersey-2.0


【解决方案1】:

问题是你如何绑定Database

bind(Database.class).to(Database.class); 

ApplicationScoped 将不起作用。您需要使用AbstractBinder 配置范围。有几种方法。

  1. 只需实例化它

    bind(new Database()).to(Database.class);
    

    这将自动使其成为单例。但是,一个问题是如果Database 有它自己的依赖项,它们将不会被注入。为此,您可以使用下一个解决方案

  2. 使用in(Scope) 方法向服务添加范围。未提供时,默认范围为PerLookup,这意味着每次请求时都会创建一个新范围。还有其他作用域,例如 SingletonRequestScope

    bind(Database.class).to(Database.class).in(Singleton.class);
    

    确保它是 javax.inject.Singleton 而不是 EJB。


在您链接到的那个问题中,您应该向下滚动到 my post :-)

【讨论】:

  • 哦,快,在链接的帖子上没有意识到你的答案,因为我主要只看被接受的那个。
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 2021-07-17
  • 2013-03-20
  • 2018-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-15
相关资源
最近更新 更多