【问题标题】:How to set context variable in JAX-RS REST-API?如何在 JAX-RS REST-API 中设置上下文变量?
【发布时间】:2018-03-16 19:23:56
【问题描述】:

我是 JAX-RS 和 REST-API 的新手。
我正在使用 REST 服务从 Oracle 获取行。我已将连接详细信息放在META-INF/context.xml<Resource> 标记中,我已在其中加密了password 变量。
我有一个自定义 Encrypter 类,我在其中使用我在 Encrypter 类中硬编码的密钥对密码进行加密/解密。
我的要求是我希望将此密钥设置在某个变量(可能是上下文变量)中,以便当用户点击像"http://server:8080/myapp/rest/replay/getdata?skey=3456FGR55566DHGGH556gf" 这样的 GET 方法 URL 时,我可以从 URL 中获取 skey 参数并将其与上下文进行比较-我从我的 Encryptor 类中设置的变量。如果两者都匹配,则显示 JSON 数据,否则将重定向到 JSP。
除了我无法在我的 Encryptor 类中设置这个 secretKey 变量之外,一切都运行良好。
以下是代码流程:

public class AuthenticatedEncryptor {

    private static final String ALGORITHM_AES256 = "AES/GCM/NoPadding";
    private final SecretKeySpec secretKeySpec;
    private final Cipher cipher;
    // All other variables...

    //@Context ServletContext context

    AuthenticatedEncryptor() throws AuthenticatedEncryptionException 
    {

        String secretKey = "9B7D2C34A366BF890C730641E6CECF6F";
        //Here I want to set the above variable in Context like:
        //context.setAttriute("skey",secretKey);

        //Code for Constructor
    }

    /*
     * Encrypts plaint text. Returns Encrypted String.
     */
    String encrypt(String plaintext) throws AuthenticatedEncryptionException
    {
        return encrypt(plaintext.getBytes(StandardCharsets.UTF_8));
    }

    String encrypt(byte[] plaintext) throws AuthenticatedEncryptionException
    {
        try 
        {
            byte[] iv = getRandom(IV_LEN);
            Cipher msgcipher = getCipher(Cipher.ENCRYPT_MODE, iv);
            byte[] encryptedTextBytes = msgcipher.doFinal(plaintext);
            byte[] payload = concat(iv, encryptedTextBytes);

            return Base64.getEncoder().encodeToString(payload);
        } 
        catch (BadPaddingException | InvalidKeyException | IllegalBlockSizeException | InvalidAlgorithmParameterException e){
            throw new AuthenticatedEncryptionException(e);
        }
    }

    /*
     * Decrypts plaint text. Returns decrypted String.
     */
    String decrypt(String ciphertext) throws AuthenticatedEncryptionException 
    {
        return decrypt(Base64.getDecoder().decode(ciphertext));
    }

    String decrypt(byte[] cipherBytes) throws AuthenticatedEncryptionException 
    {
        byte[] iv = Arrays.copyOf(cipherBytes, IV_LEN);

        byte[] cipherText = Arrays.copyOfRange(cipherBytes, IV_LEN, cipherBytes.length);
        try {
            Cipher cipher = getCipher(Cipher.DECRYPT_MODE, iv);
            byte[] decrypt = cipher.doFinal(cipherText);
            return new String(decrypt, StandardCharsets.UTF_8);
        } catch (BadPaddingException | InvalidKeyException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
            throw new AuthenticatedEncryptionException(e);
        }
    }

    //All other utility methods present here....

}

上面的类用在我自定义的DataSourceFactory类中:

public class EncryptedDataSourceFactory extends DataSourceFactory {

    private AuthenticatedEncryptor encryptor = null;

    public EncryptedDataSourceFactory() {
        try 
        {
            encryptor = new AuthenticatedEncryptor();
        } 
        catch (Exception e) {
            System.out.println("Incorrect Secret-Key specified for Decryption in EncryptedDataSourceFactory.class");
            throw new RuntimeException(e);
        }
    }

    @Override
    public DataSource createDataSource(Properties properties, Context context, boolean XA) throws Exception 
    {
        // Here we decrypt our password.
        PoolConfiguration poolProperties = EncryptedDataSourceFactory.parsePoolProperties(properties);
        poolProperties.setPassword(encryptor.decrypt(poolProperties.getPassword()));

        // The rest of the code is copied from Tomcat's DataSourceFactory.
        if(poolProperties.getDataSourceJNDI() != null && poolProperties.getDataSource() == null) {
            performJNDILookup(context, poolProperties);
        }
        org.apache.tomcat.jdbc.pool.DataSource dataSource = XA ? new XADataSource(poolProperties)
                : new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
        dataSource.createPool();

        return dataSource;
    }

}

我公开为 GET 的代码:

@Path("/replay") 
public class GetData {

    @Context
    private ServletContext context;

    Logger logger = Logger.getLogger(GetData.class.getName());

    @GET 
    @Path("/getdata")
    @Produces(MediaType.APPLICATION_JSON)
    public String getReplayData(@Context HttpHeaders httpHeaders, @Context HttpServletRequest req, @Context HttpServletResponse res)
    {

        /* Loading all HeaderParams */
        List<String> headers = new ArrayList<String>();
        for(String header : httpHeaders.getRequestHeaders().keySet()){
            headers.add(header);
        }
        //...
        //....


        /*Printing all HeaderParams */
        headerValue.forEach((k,v)->logger.info("HEADER: " + k + "-->" + v));


        /* Redirecting Code */
        //I need to access this SKEY attribute I want to set in my Encryptor
        String secretKey = (String)context.getAttribute("skey"); 
        System.out.println("SECRET KEY: "+secretKey);
        boolean redirect = false;
        String redirectVal = headerValue.get("x-test-redirect");
        if(redirectVal!=null && redirectVal.equalsIgnoreCase("Y")){
            redirect = true;
        }
        if(redirect)
        {
            try
            {
                logger.info("Authentication failed for Secret Key. Redirecting to authFailed.jsp...");
                req.getRequestDispatcher("/authFailed.jsp").forward(req, res);
            } catch(Exception e){
                System.out.println("Error in redirecting");
                logger.severe("Error in redirecting");
                logger.log(Level.SEVERE, e.getMessage(), e);
            }
        }

        OracleConn con1 = new OracleConn(env, logPath);
        ResultSet result = con1.exec("select * from mytable");
        System.out.println("Result: "+result.toString());
        logger.info("Result: "+result.toString());


        //parse data to JSON
        JSONArray json = parseJSON(result);
        System.out.println("Result parsed to JSON");
        logger.info("Result parsed to JSON");
        try{
            con1.close();
            return json.toString();

        } catch(Exception e){
            e.printStackTrace();
            logger.log(Level.SEVERE, e.getMessage(), e);
            return "Corrupted JSON";
        }


    }

}

如何在我的AuthenticatedEncryptor 类中设置一个变量并在我的网络服务类GetData 中获取它的值?

【问题讨论】:

  • CDI 可用吗?

标签: java rest web-services jax-rs


【解决方案1】:

我在这里找到了这个惊人的解决方案:
Share variables between JAX-RS requests

创建一个实现ServletContextListener的单独类:

public class ContextListener implements ServletContextListener
{
    String secretKey = "";
    @Override
    public void contextInitialized(ServletContextEvent sce)
    {
        ServletContext context = sce.getServletContext();
        secretKey = new SaltSecretKey().getSecretKey(); //My custom class
        context.setAttribute("secretKey", secretKey);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) 
    {
        ServletContext context = sce.getServletContext();
        context.removeAttribute("secretKey");
    }

}

..然后在 web.xml 中指定:

<listener>
        <listener-class>my.package.ContextListener</listener-class>
    </listener>

【讨论】:

    猜你喜欢
    • 2016-12-18
    • 2015-04-25
    • 2017-12-11
    • 2017-11-12
    • 1970-01-01
    • 2015-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多