JAX-RS安全性 - 委托人不坚持

时间:2015-11-23 08:36:15

标签: java java-ee jax-rs wildfly resteasy

首先是代码:

应用程序设置类:

    @ApplicationPath("/rest")
    public class ApplicationConfig extends Application {

    }

JAX-RS资源类:

    @Path("/test")
    @RequestScoped
    public class TestWS {
        @POST
        @Path("/login")
        @Produces(MediaType.TEXT_PLAIN)
        public Response login(@Context HttpServletRequest req){
            req.getSession().setAttribute("test","test");
            System.out.println(req.getSession().getId());
            if(req.getUserPrincipal() == null){
                String authHeader = req.getHeader(HttpHeaders.AUTHORIZATION);
                if(authHeader != null && !authHeader.isEmpty()){
                    String base64Credentials = authHeader.substring("Basic".length()).trim();
                    String credentials = new String(Base64.getDecoder().decode(base64Credentials),
                            Charset.forName("UTF-8"));
                    final String[] values = credentials.split(":",2);
                    try {
                        req.login(values[0], values[1]);
                        System.out.println(req.getUserPrincipal().toString());
                    }
                    catch(ServletException e){
                        e.printStackTrace();
                        return Response.status(Response.Status.UNAUTHORIZED).build();
                    }
                }
            }else{
                System.out.println(req.getUserPrincipal());
                System.out.println(req.isUserInRole("User"));
                req.getServletContext().log("Skipped logged because already logged in!");
            }

            req.getServletContext().log("Authentication Demo: successfully retrieved User Profile!");
            return Response.ok().build();
        }

        @Path("/ping")
        @Produces(MediaType.APPLICATION_JSON)
        @GET
        public String ping(@Context HttpServletRequest req){
            Object test = req.getSession().getAttribute("test");
            System.out.println(req.getSession().getId());
            System.out.println(test);
            System.out.println(req.getUserPrincipal());
            System.out.println(req.isUserInRole("User"));
            return "{\"status\":\"ok\"}";
        }
    }

的web.xml:

    <?xml version="1.0" encoding="UTF-8" ?>
    <web-app>
        <context-param>
            <param-name>resteasy.role.based.security</param-name>
            <param-value>true</param-value>
        </context-param>

        <security-constraint>
            <web-resource-collection>
                <web-resource-name>rest</web-resource-name>
                <url-pattern>/rest/*</url-pattern>
                <http-method>GET</http-method>
                <http-method>POST</http-method>
                <http-method>PUT</http-method>
                <http-method>DELETE</http-method>
            </web-resource-collection>
            <user-data-constraint>
                <transport-guarantee>NONE</transport-guarantee>
            </user-data-constraint>
        </security-constraint>

        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
        </welcome-file-list>

        <session-config>
            <session-timeout>30</session-timeout>
        </session-config>

        <login-config>
            <auth-method>BASIC</auth-method>
            <realm-name>PBKDF2DatabaseDomain</realm-name>
        </login-config>
    </web-app>

的JBoss-web.xml中

    <?xml version="1.0" encoding="UTF-8"?>
    <jboss-web>
        <context-root>/</context-root>
        <security-domain>PBKDF2DatabaseDomain</security-domain>
    </jboss-web>

standalone.xml中的安全设置

    <subsystem xmlns="urn:jboss:domain:security:1.2">
        <security-domains>
            <security-domain name="PBKDF2DatabaseDomain" cache-type="default">
                <authentication>
                    <login-module code="de.rtner.security.auth.spi.SaltedDatabaseServerLoginModule" flag="required" module="de.rtner.PBKDF2">
                        <module-option name="dsJndiName" value="java:jboss/datasources/developmentDS"/>
                        <module-option name="principalsQuery" value="SELECT password FROM ur.user WHERE username=?"/>
                        <module-option name="rolesQuery" value="select distinct r.NAME, 'Roles' from ur.user_roles ur left join ur.ct_role r on ur.ROLE_ID = r.ID left join ur.user u on ur.USER_ID = u.ID where u.username =?"/>
                    </login-module>
                </authentication>
            </security-domain>
...

现在我的问题是,在请求中使用带有BASIC auth头的/ login方法后,我已经获得了用户主体,因此打印出来:

已删除记录,因为已登录!

如果我从请求中删除BASIC auth标头并再次调用login,我仍然得到相同的打印输出 - 所以我已经在请求中有用户主体 - 不需要req.login。

但是,如果我调用ping方法,则即使会话ID相同且设置了会话属性,用户主体也为空。我究竟做错了什么?我希望用户主体像/登录一样坚持/ ping。

我正在使用Wildfly 10(RESTeasy jax-rs实现)

我的问题是类似于: JBOSS AS7 jax-rs jaas and annotations

但是登录方法中的修复设置会话属性对我不起作用。

1 个答案:

答案 0 :(得分:1)

一些提示和评论:

  • 由于REST是无状态的,我会在客户端管理会话,而不是在服务器端保持客户端状态。
  • 无状态身份验证可以通过将您希望仅限于经过身份验证的用户的每个请求/服务发送回BASIC身份验证标头来实现,例如/ login和/ ping
  • / login服务可能只是在用户未经过良好身份验证和识别时抛出WebApplicationException,以便客户端应用程序对其进行管理并向最终用户显示身份验证错误消息。 然后,您可以使用@RolesAllowed(&#39;某些&#39;)注释与您的/ ping方法之上的JAAS来限制对具有“&#39;某事物”的经过身份验证的用户的访问权限。角色。因此,您不再需要编写身份验证或授权代码,并且可以从应用程序中的授权层中受益。

所有这一切都可以在Wildfly上使用Java EE 7实现,而且不需要额外的库。