Spring MVC、RESTful 服务和 Apache Shiro 策略

Posted

技术标签:

【中文标题】Spring MVC、RESTful 服务和 Apache Shiro 策略【英文标题】:Spring MVC, RESTful Services & Apache Shiro Strategy 【发布时间】:2011-07-20 07:25:12 【问题描述】:

我正忙于一个需要 REST API 以允许用户访问他们在服务器上的信息的项目。我让系统使用 Spring MVC 和 MappingJacksonJsonView 在需要的地方返回 JSON。

我现在想在系统中包含安全性,首先,确保用户进行身份验证并拥有访问资源的正确权限,其次我希望对数据进行足够细粒度的控制,以确保用户只能访问资源的公开可用部分,或者如果他们拥有整个资源的正确权限。

例如:

场景 A:用户 A 想要访问他们的消息列表以及他们的姓名和电话号码。然后他们将获得身份验证,他们的权限将允许他们访问自己的所有信息。

场景 B: 用户 A 想要访问用户 B 的电话号码 - 因此在响应中排除用户 B 的消息列表,因为 A 无权访问该部分信息。

Q1:有没有一种简洁的方法 关于使用 Apache Shiro 执行此操作 和 Spring MVC? Q2:有没有人 有一个示例或教程链接 关于别人是如何取得成就的 这? Q3:什么样的权限 使用 Shiro 的方案将是最 有效地允许这种类型的罚款 粒度控制?

我以前没有与 Shiro 合作过,但是从玩示例和阅读文档来看,这是可能的,而且 Shiro 最适合解决方案。不过,我对其他解决方案持开放态度。

编辑:一种解决方案,我不知道 Shiro 和 Jackson 是否可行,是在我的 POJO 中注释属性,我可以将其标记为公共或私有。或者更好的是,用访问它们所需的权限标记它们。然后当 Jackson 打印出对象的 JSON 表示时,它可以检查当前属性的权限,并从其注释中决定是否打印该属性。

【问题讨论】:

【参考方案1】:

这个问题的解决方案非常简单。我为 Jackson 创建了一组视图类:

public class SecureViews 
    public static class Public;
    public static class Authenticated extends Public;
    public static class User extends Authenticated;
    public static class Internal extends User ;

然后,我通过添加以下内容为我想要保护的每个实体注释了所有 getter 方法:

@JsonView(SecureViews.Authenticated.class)
public String getPhoneNumber() 
    return phoneNumber;

上述规则的意思是,只有在系统内通过身份验证的用户才能查看用户的电话号码。

或者

@JsonView(SecureViews.User.class)
public List<Event> getEvents() 
    return Collections.unmodifiableList(events);

然后我创建了一个接口并在我的所有安全实体中实现了该接口:

public interface SecurePropertyInterface 
    Class<?> getMaxPermissionLevel(Long userID);

这是该方法的实现:

public Class<?> getMaxPermissionLevel(Long userID) 
        if (userID != null && userID == uid) 
            return SecureViews.User.class;
        
        if (SecurityUtils.getSubject().isAuthenticated()) 
            return SecureViews.Authenticated.class;
        

        return SecureViews.Public.class;
    

现在是魔术。扩展MappingJacksonJsonView并覆盖以下方法:

@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
            HttpServletResponse response) throws Exception 

        Long userID = CTConversionUtils.convertToLong(request.getParameter("id"));
        model = (Map<String, Object>) super.filterModel(model);

        Class<?> viewClass = SecureViews.Public.class;

        if(SecurityUtils.getSubject().isAuthenticated()) 
            viewClass = SecureViews.Authenticated.class;
        

        for (Entry<String, Object> modelEntry : model.entrySet()) 
            if (modelEntry.getValue() instanceof SecurePropertyInterface) 
                viewClass = ((SecurePropertyInterface)modelEntry.getValue()).getMaxPermissionLevel(userID);
            
        
        objectMapper.viewWriter(viewClass).writeValue(getJsonGenerator(response), model);
    

当 Spring 设置您的 MappingJacksonJsonView 时,您还可以覆盖 setObjectMapper 方法来捕获 objectMapper。

我的 Spring 配置如下所示:

<bean
        class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
        p:order="1">
        <property name="mediaTypes">
            <map>
                <entry key="json" value="*/*" />
            </map>
        </property>
        <property name="defaultViews">
            <list>
                <bean
                    class="com.bytesizecreations.connecttext.json.SecureMappingJacksonJsonView">
                    <property name="objectMapper">
                        <bean
                            class="org.codehaus.jackson.map.ObjectMapper" />
                    </property>
                </bean>
            </list>
        </property>
    </bean>

那么我们现在有什么?每次需要将响应反序列化为 JSON 时,都会调用 renderMergedOutputModel 方法。如果用户的 id 在我们存储的请求中。然后我们可以遍历模型映射并检查每个值是否是 SecurePropertyInterface 以及是否获得其最大权限级别。

这个策略似乎很符合我的目的。当用户请求用户列表时,他们只会获得经过身份验证的属性,但当用户请求自己的详细信息时,他们只会获得他们的私有属性。

我怀疑这段代码可以进一步改进,但我花了太多时间试图让它不那么复杂。

【讨论】:

您可以使用Class&lt;?&gt; 并取消原始类型警告。

以上是关于Spring MVC、RESTful 服务和 Apache Shiro 策略的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 RestTemplate 在 Spring MVC 应用程序中访问来自(来自 Spring RESTful 服务)的巨大 JSON

将 GZIP 压缩与 Spring Boot/MVC/JavaConfig 与 RESTful 结合使用

如何将跨域资源共享与 Spring MVC 4.0.0 RESTful Webservice 集成

java spring mvc restful 上传文件

Spring MVC对restful的支持

Spring MVC对restful的支持