gpt4 book ai didi

java - Spring MVC、RESTful 服务和 Apache Shiro 策略

转载 作者:行者123 更新时间:2023-11-30 11:54:50 25 4
gpt4 key购买 nike

我正忙于一个项目,该项目需要一个 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 中注释我可以标记为公共(public)或私有(private)的属性。或者更好的是,用访问它们所需的权限标记它们。然后,当 Jackson 打印出对象的 JSON 表示时,它可以检查当前属性的权限,并根据其注释决定是否打印该属性。

最佳答案

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

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);
}

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

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 时,都会调用 renderedMergedOutputModel 方法。如果用户的 ID 在我们存储的请求中。然后我们可以遍历模型映射并检查每个值是否是 SecurePropertyInterface 以及它是否获得了最大权限级别。

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

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

关于java - Spring MVC、RESTful 服务和 Apache Shiro 策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5388687/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com