JAX-RS(Jersey 2)安全性,@ PermitAll和@RolesAllowed无法按预期工作 [英] JAX-RS (Jersey 2) security, @PermitAll and @RolesAllowed not working as expected

查看:71
本文介绍了JAX-RS(Jersey 2)安全性,@ PermitAll和@RolesAllowed无法按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有三个资源的REST-API.第一个中的方法称为PublicResource,任何人都应该可以访问(即匿名访问).第二个方法中的方法称为SecretResource,只应允许特定的用户组访问.最后,第三个资源(称为MixedResource)具有混合设置,其中一些方法受到保护,而另一些则开放给公众访问.

I have a REST-API with three resources. The methods in the first one, called PublicResource, should be accessible for anyone (i.e. anonymous access). The methods in the second one, called SecretResource, should only be accessible for a specific group of users. Finally, the third resource, called MixedResource, has a mixed setup with some method being protected and some being open for public access.

注解@PermitAll和@RolesAllowed无法正常运行,因为我期望它们能正常运行.尽管PublicResource带有@PermitAll批注,但在尝试访问它时仍会被要求授权.用@PermitAll注释的MixedResource中的方法也是如此.因此,基本上,即使我应该具有匿名访问权限,我也会在所有资源中到处都要求获得授权.

The annotations @PermitAll and @RolesAllowed don't work as I'm expecting them to though. Although PublicResource is annotated with @PermitAll I'm still getting asked for authorization when trying to access it. The same goes for the methods in MixedResource that are annotated with @PermitAll. So basically, I'm getting asked for authorization everywhere in all of my resources even were I should have anonymous access.

我在Payara 4.1上运行,我感到非常困惑,因为我在另一个运行在WebLogic 12.1.3上的应用程序中进行了非常相似的设置,并且注释按预期工作.我想念什么或弄错了什么?请参阅下面的完整代码.

I'm running on Payara 4.1 and I'm very confused since I had a very similar setup in another app running on WebLogic 12.1.3 and there the annotations worked as expected. What am I missing or getting wrong? See my full code below.

PublicResource.java:

PublicResource.java:

    import javax.annotation.security.PermitAll;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;

    @Path("public")
    @PermitAll
    public class PublicResource {

        @GET
        @Produces(MediaType.TEXT_PLAIN)
        public String itsPublic() {
            return "public";
        }

    }

SecretResource.java:

SecretResource.java:

    import javax.annotation.security.RolesAllowed;
    import javax.ws.rs.GET;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;

    @Path("secret")
    @RolesAllowed({ "SECRET" })
    public class SecretResource {

        @GET
        @Produces(MediaType.TEXT_PLAIN)
        public String itsSecret() {
            return "secret";
        }

    }

MixedResource.java:

MixedResource.java:

    import javax.annotation.security.PermitAll;
    import javax.annotation.security.RolesAllowed;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;

    @Path("mixed")
    @PermitAll
    public class MixedResource {

        @GET
        @Path("public")
        @Produces(MediaType.TEXT_PLAIN)
        public String itsPublic() {
            return "public";
        }

        @GET
        @Path("secret")
        @RolesAllowed({ "SECRET" })
        @Produces(MediaType.TEXT_PLAIN)
        public String itsSecret() {
            return "secret";
        }

    }

JAXRSConfiguration.java:

JAXRSConfiguration.java:

    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;

    @ApplicationPath("resources")
    public class JAXRSConfiguration extends Application {

    }

web.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
        <session-config>
            <session-timeout>30</session-timeout>
        </session-config>
        <security-constraint>
            <web-resource-collection>
                <web-resource-name>Basic Authorization</web-resource-name>
                <description/>
                <url-pattern>/resources/*</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>SECRET</role-name>
            </auth-constraint>
        </security-constraint>
        <login-config>
            <auth-method>BASIC</auth-method>
            <realm-name>file</realm-name>
        </login-config>
        <error-page>
            <exception-type>java.lang.Throwable</exception-type>
            <location>/error/internal</location>
        </error-page>
        <security-role>
            <role-name>SECRET</role-name>
        </security-role>
    </web-app>

glassfish-web.xml:

glassfish-web.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
    <glassfish-web-app error-url="">
        <class-loader delegate="true"/>
        <security-role-mapping>
            <role-name>SECRET</role-name>
            <group-name>cia</group-name>
        </security-role-mapping>
        <jsp-config>
            <property name="keepgenerated" value="true">
                <description>Keep a copy of the generated servlet class' java code.</description>
            </property>
        </jsp-config>
    </glassfish-web-app>

beans.xml:

beans.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
   bean-discovery-mode="all">
    </beans>

推荐答案

从表面上看,这不是Jersey的问题.您配置的唯一真正的安全性是在servlet容器级别.您的Jersey安全性注释都没有任何作用,因为您甚至都没有为其配置特定于Jersey的支持.

At the face of it, this is not a problem with Jersey. The only real security you have configured is at the servlet container level. None of your Jersey security annotations have any effect, as you haven't even configured the Jersey specific support for it.

首先查看您的web.xml配置

First look at you web.xml configuration

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Basic Authorization</web-resource-name>
        <description/>
        <url-pattern>/resources/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>SECRET</role-name>
    </auth-constraint>
</security-constraint>

第一部分设置每个资源都需要身份验证.因此,您认为的问题是@PermitAll无法正常工作的原因,实际上是由于您配置servlet不允许任何未经身份验证的人通过而造成的.

The first part sets up that every resource requires authentication. So what you think is a problem with @PermitAll not working, is actually caused by the fact that you configured servlet to not let anyone through that is not authenticated.

然后在servlet容器级别设置授权,以仅允许具有SECRET角色的用户.因此,您的所有安全配置都在web.xml中进行了配置.与泽西岛无关.

Then you set up the authorization at the servlet container level to only allow users with the SECRET role. So all your security configuration is configured here in the web.xml. Nothing to do with Jersey.

要解决此问题,您还需要了解的另一件事是身份验证和授权之间的区别,以及谁在其中扮演什么角色(关于servlet容器和Jersey).

The other thing you need to understand to fix this problem, is the difference between authentication and authorization, and who plays a role in what (with regards to the servlet container and Jersey).

@PermitAll@RolesAllowed等仅是Jersey处理授权的方式.预计已经有一个经过身份验证的用户.泽西(Jersey)的检查方法是通过从Servlet请求中获取主体.如果没有主体,则假定没有经过身份验证的用户,并且即使您拥有@PermitAll,也将不允许任何人通过,因为即使@PermitAll都要求用户已验证.

The @PermitAll, @RolesAllowed, etc are only ways of Jersey handling authorization. It is expected that there already be an authenticated user. How Jersey checks this is by getting the principal from the servlet request. If there is no principal, then it is assumed that there is not authenticated user, and then will not allow anyone through, even if you have @PermitAll, as even @PermitAll requires a user to be authenticated.

话虽这么说,但我不知道有没有一种方法可以在您的服务器中设置匿名用户.这是获得所需行为所需要的.请记住,Jersey仍然需要有经过身份验证的用户.因此,除非您能以某种方式在该容器中设置匿名用户,否则我看不到您可以进行此工作.

That being said, I don't know is there's a way to set an anonymous user in your server. This is what would be required to get the behavior you want. Remember that Jersey still requires that there be an authenticated user. So unless you can somehow set an anonymous user at the container, I don't see you could make this work.

如果您为安全和非安全设置了不同的路径,则可以只在web.xml中配置安全的路径,然后放开其他所有内容.这样,甚至不需要@PermitAll.请记住,使用@PermitAll,它需要经过身份验证的用户.但是,如果只删除@PermitAll,则所有请求都将通过.如果您将安全和非安全之间的路径分开,这将是可能的.

If you had different paths though for secured and not secured, then you could just configure the secured paths in the web.xml, and everything else just let go. With this, there wouldn't even be a need for @PermitAll. Remember, with @PermitAll, it requires an authenticated user. But if you just remove the the @PermitAll, then all requests would just go through. This would be possible if you separated the paths between secured and not secured.

如果您想对所有这些进行更多控制,那么最好实现自己的安全性,而不要使用servlet容器的安全性.通常我不建议这样做,但是基本身份验证可能是最容易实现的安全协议.您可以查看此示例,其中所有内容都是使用Jersey过滤器完成.

If you want more control over all this, you might be better off implementing your own security instead of using the servlet container's. Normally I wouldn't recommend this, but Basic Authentication is probably the easiest security protocol to implement. You can check out this example, where everything is done using Jersey filters.

要注意的最后一件事是,您甚至尚未配置对Jersey的授权支持.您仍然需要在应用程序中注册RolesAllowedDynamicFeature.由于您正在为JAX-RS配置使用类路径扫描(空的应用程序类),因此您需要从Feature注册它,如

The last thing to note is the fact that you haven't even configured the authorization support for Jersey. You still need to register the RolesAllowedDynamicFeature with the application. Since you are using classpath scanning (empty Application class) for your JAX-RS configuration, then you will need to register it from a Feature, as mentioned in this post

这篇关于JAX-RS(Jersey 2)安全性,@ PermitAll和@RolesAllowed无法按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆