11

Spring Security ロールに基づいて JSON 出力をフィルタリングする良い方法はありますか? @JsonIgnore のようなものを探していますが、@HasRole("ROLE_ADMIN") のようなロールを探しています。これをどのように実装すればよいですか?

4

3 に答える 3

9

更新: 新しい回答

rkonovalov/jfilter の使用を検討する必要があります。特に@DynamicFilterComponent大いに役立ちます。このDZone の記事で良いガイドを見ることができます。

@DynamicFilterComponentここで説明します。

古い答え

上記の要件を実装しました。私のシステムは Restful Jersey 1.17Spring Security 3.0.7、を使用していJackson 1.9.2ます。ただし、ソリューションは Jersey Restful API とは関係なく、他の種類のサーブレット実装で使用できます。

これは、私のソリューションの 5 つのステップ全体です。

  1. まず、次のように、目的に合わせて Annotation クラスを作成する必要があります。

    JsonSpringView.java

    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Retention(RetentionPolicy.RUNTIME)
    public @interface JsonSpringView {
        String springRoles();
    }
    
  2. 次に、Annotation Introspector、そのほとんどのメソッドが返さnullれ、必要に応じてメソッドを入力します。使用したばかりの要件に対応しますisIgnorableFieldFeatureGrantedAuthority インターフェイスの私の実装です。このような:

    JsonSpringViewAnnotationIntrospector.java

    @Component
    public class JsonSpringViewAnnotationIntrospector extends AnnotationIntrospector implements Versioned 
    {
        // SOME METHODS HERE
        @Override
        public boolean isIgnorableField(AnnotatedField)
        {
            if(annotatedField.hasAnnotation(JsonSpringView.class))
            {
                JsonSpringView jsv = annotatedField.getAnnotation(JsonSpringView.class);
                if(jsv.springRoles() != null)
                {
                    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
                    if(principal != null && principal instanceof UserDetails)
                    {
                        UserDetails principalUserDetails = (UserDetails) principal;
                        Collection<? extends  GrantedAuthority> authorities = principalUserDetails.getAuthorities();
                        List<String> requiredRoles = Arrays.asList(jsv.springRoles().split(","));
    
                        for(String requiredRole : requiredRoles)
                        {
                            Feature f = new Feature();
                            f.setName(requiredRole);
                            if(authorities.contains(f))
                            // if The Method Have @JsonSpringView Behind it, and Current User has The Required Permission(Feature, Right, ... . Anything You may Name It).
                            return false;
                        }
                        // if The Method Have @JsonSpringView Behind it, but the Current User doesn't have The required Permission(Feature, Right, ... . Anything You may Name It).
                        return true;
                    }
                }
            }
            // if The Method Doesn't Have @JsonSpringView Behind it.
            return false;
        }
    }
    
  3. Jersey サーバーには、ObjectMapperシリアライゼーション/デシリアライゼーション用のデフォルトがあります。このようなシステムを使用していて、デフォルトの ObjectMapper を変更したい場合は、ステップ 3、4、および 5 があなたのものです。

    JsonSpringObjectMapperProvider.java

    @Provider
    public class JsonSpringObjectMapperProvider implements ContextResolver<ObjectMapper>
    {
        ObjectMapper mapper;
    
        public JsonSpringObjectMapperProvider()
        {
            mapper = new ObjectMapper();
            AnnotationIntrospector one = new JsonSpringViewAnnotationIntrospector();
            AnnotationIntrospector two = new JacksonAnnotationIntrospector();
            AnnotationIntrospector three = AnnotationIntrospector.pair(one, two);
    
            mapper.setAnnotationIntrospector(three);
        }
    
        @Override
        public ObjectMapper getContext(Class<?> arg0) {
            return this.mapper;
        }
    }
    
  4. javax.ws.rs.core.ApplicationWeb.xml でクラス名を拡張して言及する必要があります。私のはRestApplication.Likeです:

    RestApplication.java

    import java.util.HashSet;
    import java.util.Set;
    
    import javax.ws.rs.core.Application;
    
    public class RestApplication extends Application
    {
        public Set<Class<?>> getClasses() 
        {
            Set<Class<?>> classes = new HashSet<Class<?>>();
            classes.add(JsonSpringObjectMapperProvider.class);
            return classes ;
        }
    }
    
  5. これが最後のステップです。web.xml で Application クラス (ステップ 4 から) に言及する必要があります。

    私のweb.xmlの一部

    <servlet>
        <servlet-name>RestService</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.package</param-name>
            <param-value>your_restful_resources_package_here</param-value>
        </init-param>
        <init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <!-- THIS IS THE PART YOU SHOULD PPPAYYY ATTTTENTTTTION TO-->
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>your_package_name_here.RestApplication</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    

そしてこれからは、必要なプロパティの背後にある @JsonSpringView アノテーションに言及するだけです。このような:

PersonDataTransferObject.java

public class PersonDataTransferObject
{
    private String name;

    @JsonSpringView(springRoles="ADMIN, SUPERUSER")  // Only Admins And Super Users Will See the person National Code in the automatically produced Json.
    private String nationalCode;
}
于 2013-09-19T13:51:52.820 に答える