简体   繁体   English

球衣安全和会话管理

[英]jersey security and session management

Is there a way to get session management or security programatically in Jersey, eg web-application session management? 有没有办法在Jersey中以编程方式获得会话管理或安全性,例如Web应用程序会话管理? Or are transactions, sessions, and security all handled by the container in which the Jersey application is deployed? 或者,事务,会话和安全性是否都由部署Jersey应用程序的容器处理?

Session management is the purview of the container in which Jersey is deployed. 会话管理是部署Jersey的容器的范围。 In most production cases, it will be deployed within a container that performs session management. 在大多数生产案例中,它将部署在执行会话管理的容器中。

The code below is a simple example of a jersey resource that gets the session object and stores values in the session and retrieves them on subsequent calls. 下面的代码是一个简单的球衣资源示例,它获取会话对象并在会话中存储值并在后续调用中检索它们。

@Path("/helloworld")
public class HelloWorld {

    @GET
    @Produces("text/plain")
    public String hello(@Context HttpServletRequest req) {

        HttpSession session= req.getSession(true);
        Object foo = session.getAttribute("foo");
        if (foo!=null) {
            System.out.println(foo.toString());
        } else {
            foo = "bar";
            session.setAttribute("foo", "bar");
        }
        return foo.toString();


    }
}

I thought that sessions is something we should never use in RESTful applications... 我认为,会议是我们永远不应该在RESTful应用程序使用...

Yegor is right. 叶戈尔是对的。 We shouldn't never maintain state in the server side a la conventional web application. 在服务器端一拉传统的Web应用程序,我们不应该永远保持状态。 If you want to build a decoupled SOA-oriented application you don't need to use any API/framework for REST web services. 如果要构建一个分离的面向SOA的应用程序,则不需要使用任何API /框架来进行REST Web服务。 If you need, or want, to maintain the global client-server state in the server side you are implicitly building what we could describe as a SOA-oriented [web]app, but using Jersey like a [web] development framework of sorts. 如果您需要或希望在服务器端维护全局客户端 - 服务器状态,那么您将隐式构建我们可以描述为面向SOA的[Web]应用程序,但是使用Jersey就像[web]开发框架一样。 Inadvertently you are twisting the nature of a web service (REST or otherwise). 无意中,您正在扭曲Web服务(REST或其他)的本质。 You can do it in the way it's been suggested in the first answer, but you mustn't . 可以按照第一个答案中建议的方式进行,但您不能这样做 The final result is not a web service, just a regular app constructed with web services' tools. 最终结果不是Web服务,只是使用Web服务工具构建的常规应用程序。

-_o -_o

Yes it's possible. 是的,这是可能的。 Jersey documentation says: 泽西文件说:

Security information of a request is available by injecting a JAX-RS SecurityContext instance using @Context annotation. 通过使用@Context注释注入JAX-RS SecurityContext实例,可以获得请求的安全信息。 The injected security context instance provides the equivalent of the functionality available on HttpServletRequest API. 注入的安全上下文实例提供HttpServletRequest API上可用功能的等效项。 The injected security context depends on the actual Jersey application deployment. 注入的安全上下文取决于实际的Jersey应用程序部署。 For example, for a Jersey application deployed in a Servlet container, the Jersey SecurityContext will encapsulate information from a security context retrieved from the Servlet request. 例如,对于部署在Servlet容器中的Jersey应用程序,Jersey SecurityContext将封装来自从Servlet请求检索的安全上下文的信息。 In case of a Jersey application deployed on a Grizzly server, the SecurityContext will return information retrieved from the Grizzly request. 如果在Grizzly服务器上部署了Jersey应用程序,SecurityContext将返回从Grizzly请求中检索到的信息。

Example: 例:

@Path("basket")
public ShoppingBasketResource get(@Context SecurityContext sc) {
    if (sc.isUserInRole("PreferredCustomer") {
        return new PreferredCustomerShoppingBasketResource();
    } else {
        return new ShoppingBasketResource();
    }
}

or 要么

@Path("resource")
@Singleton
public static class MyResource {
    // Jersey will inject proxy of Security Context
    @Context
    SecurityContext securityContext;

    @GET
    public String getUserPrincipal() {
        return securityContext.getUserPrincipal().getName();
    }
}

Or if you want security out of the box with annotations check these docs . 或者,如果您想要开箱即用的安全注释,请检查这些文档

Jersey also allows you to customize the SecurityContext: Jersey还允许您自定义SecurityContext:

The SecurityContext can be directly retrieved from ContainerRequestContext via getSecurityContext() method. 可以通过getSecurityContext()方法从ContainerRequestContext直接检索SecurityContext。 You can also replace the default SecurityContext in a request context with a custom one using the setSecurityContext(SecurityContext) method. 您还可以使用setSecurityContext(SecurityContext)方法将请求上下文中的默认SecurityContext替换为自定义SecurityContext。 If you set a custom SecurityContext instance in your ContainerRequestFilter, this security context instance will be used for injection into JAX-RS resource class fields. 如果在ContainerRequestFilter中设置自定义SecurityContext实例,则此安全上下文实例将用于注入JAX-RS资源类字段。 This way you can implement a custom authentication filter that may setup your own SecurityContext to be used. 这样,您就可以实现自定义身份验证筛选器,该筛选器可以设置您自己的SecurityContext以供使用。 To ensure the early execution of your custom authentication request filter, set the filter priority to AUTHENTICATION using constants from Priorities. 要确保提前执行自定义身份验证请求筛选器,请使用“优先级”中的常量将筛选器优先级设置为AUTHENTICATION。 An early execution of you authentication filter will ensure that all other filters, resources, resource methods and sub-resource locators will execute with your custom SecurityContext instance. 早期执行身份验证筛选器将确保所有其他筛选器,资源,资源方法和子资源定位器将与您的自定义SecurityContext实例一起执行。

See examples on how to use request filters with Jersey . 请参阅有关如何使用Jersey的请求过滤器的示例 And check my following example: 并查看以下示例:

import javax.annotation.Priority;
import javax.ws.rs.Priorities;

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthRequestFilter implements ContainerRequestFilter {
    @Context
    HttpServletRequest webRequest;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        final HttpSession session = webRequest.getSession();

        requestContext.setSecurityContext(new SecurityContext() {
            @Override
            public Principal getUserPrincipal() {
                return new PrincipalImpl((String)session.getAttribute("USER_NAME"));
            }

            @Override
            public boolean isUserInRole(String s) {
                return false;
            }

            @Override
            public boolean isSecure() {
                return false;
            }

            @Override
            public String getAuthenticationScheme() {
                return null;
            }
        });
    }
}

Warning! 警告! This was introduced in Jersey 2.4 . 这是在泽西岛2.4中引入的 Glassfish 4.0.0 uses old Jersey 2.0 therefore you will have to upgrade Jersey using these tips (it's not proven to work well). Glassfish 4.0.0使用旧的Jersey 2.0,因此你必须使用这些技巧升级泽西岛 (它没有被证明效果很好)。 Or the better way is to download the nightly build of Glassfish 4.0.1 . 或者更好的方法是下载Glassfish 4.0.1的每晚版本 but it's not completely stable at the moment. 但目前还不完全稳定。 I hope the new version will be released soon. 我希望新版本即将发布。

UPDATE: At the moment (2014-02-14) Glassfish 4.0.1 nightly build uses Jersey 2.5.1 and context injection works great. 更新:目前(2014-02-14)Glassfish 4.0.1每晚构建使用Jersey 2.5.1并且上下文注入效果很好。

Jack's response about sessions is correct. 杰克对会议的回应是正确的。 They are specific to the container that you execute in, although the Servlet spec at least gives you portability between JavaEE containers. 它们特定于您执行的容器,尽管Servlet规范至少为您提供了JavaEE容器之间的可移植性。

As for security, you at least have the opportunity to separate it from your JAX-RS specific code by employing JaaS (Java Authentication and Authorization Service) and a servlet filter . 至于安全性,您至少有机会通过使用JaaS(Java身份验证和授权服务)和servlet过滤器将其与JAX-RS特定代码分开。 The filter can be used to enforce HTTP authentication and, on successful auth, setup the JaaS Subject with the appropriate Principals. 过滤器可用于强制执行HTTP身份验证,并且在成功验证后,使用适当的主体设置JaaS主题。 Your JAX-RS resources can check for the appropriate Principals on the Subject. 您的JAX-RS资源可以检查主题上的相应主体。 Since you control the whole stack, you should be able to rely on an authenticated user in your resources (but do test this!), and you can enforce authorization based on the current operation in the resource code. 由于您控制整个堆栈,您应该能够依赖资源中经过身份验证的用户(但要对此进行测试!),并且您可以根据资源代码中的当前操作强制执行授权。

I solved this problem by having the clients add the Authorization header and testing it in the REST methode like this: 我通过让客户端添加Authorization标头并在REST方法中测试它来解决这个问题,如下所示:

@GET
@PRODUCES(MediaType.APPLICATION_JSON)
public String returnClients(@Context HTTPServletRequest request(
    String auth = request.getHeader("Authorization");
    Account acc = null;
    if (auth!=null) {
       Account acc = Utils.LoginAccount(auth);
    }
    if (acc == null)
     // not logged in, handle it gracefully

This way there is authentication without starting a session. 这样,无需启动会话即可进行身份验证。

For Jersey security you should take a look on jersey OAuth support. 对于Jersey安全,你应该看看球衣OAuth支持。 OAuth perfectly fits when you expose API for your system to external users. 当您将系统的API公开给外部用户时,OAuth非常适合。 For example like the linkedin api 例如像linkedin api

http://wikis.oracle.com/display/Jersey/OAuth http://wikis.oracle.com/display/Jersey/OAuth

You can user @path to group the services under single name space. 您可以使用@path在单个名称空间下对服务进行分组。 example . 例子。

@Path("/helloworld")
public class HelloWorld {

    @GET
    @Produces("text/plain")
    public String hello() {


        return "";


    }
}
Instead of @Path("/helloworld") use
@Path("admin/helloworld") to expose you class as rest and bind filter on "admin/"
in web.xml as below.

<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>/</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>jersey-serlvet</servlet-name>
            <url-pattern>/rest/*</url-pattern>
        </servlet-mapping>
         <filter>
            <filter-name>myfilter</filter-name>
            <filter-class>com.Filterclass</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>myfilter</filter-name>
            <url-pattern>/rest/admin/*</url-pattern>
        </filter-mapping> 

    public class Filterclass implements Filter {
       public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain)
                throws IOException, ServletException {
                  try{
                       chain.doFilter(request, response);
                    }catch(Exception e){
                   e.printStackTrace();
                       }
          }
    }

You can validate you session in this filter class. 您可以在此过滤器类中验证您的会话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM