【问题标题】:Struts2- URL tag - Hide query StringStruts2- URL 标记 - 隐藏查询字符串
【发布时间】:2013-02-19 03:53:10
【问题描述】:

在对 stackoverflow 进行大量研究后,我发布了这个问题,因为我找不到该问题的解决方案。

需求场景:根据每个客户 ID 作为参数,从客户列表中更新客户。

尝试的解决方案:根据从jsp收到的客户ID,将其作为Struts2 url标签传递给Action。

面临的问题 - URL 上可见的查询字符串。
http://foo.com/Struts2Example/getCustomerAction?customerId=2

问题:

  1. 如果我们使用struts Url标签,我们可以不隐藏查询字符串吗?
  2. 如果我们在使用 Url 标签时无法隐藏 using 查询字符串?上述情况的替代方案是什么。

下面的struts.xml、jsp和动作代码-

<h2>All Customers Details</h2>

<s:if test="customerList.size() > 0">
    <table border="1px" cellpadding="8px">
        <tr>
            <th>Customer Id</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Age</th>
            <th>Created Date</th>
        </tr>
        <s:iterator value="customerList" status="userStatus">
            <tr>
                <td><s:url var="editCustomer" action="getCustomerAction">
                        <s:param name="customerId" value="%{customerId}" />
                    </s:url>

                    <p>
                        <s:a href="%{editCustomer}">
                            <s:property value="customerId" />
                        </s:a>
                    </p></td>

                <td><s:property value="firstname" /></td>
                <td><s:property value="lastname" /></td>
                <td><s:property value="age" /></td>
                <td><s:date name="createdDate" format="dd/MM/yyyy" /></td>
            </tr>
        </s:iterator>
    </table>
</s:if>
<br />
<br />

struts.xml-

<!-- Get Customer Details - To Pre-Populate the form to update a Customer -->
    <action name="getCustomerAction" method="getCustomerById"
        class="com.hcl.customer.action.CustomerAction">
        <result name="success">pages/customerForm.jsp </result>
    </action>

客户操作类-

public class CustomerAction extends ActionSupport implements ModelDriven {

Logger logger = Logger.getLogger(CustomerAction.class);

Customer customer = new Customer();

List<Customer> customerList = new ArrayList<Customer>();
CustomerDAO customerDAO = new CustomerDAOImpl();

public Customer getCustomer() {
    return customer;
}

//Set Customer onto Value Stack
public void setCustomer(Customer customer) {
    this.customer = customer;
}

public List<Customer> getCustomerList() {
    return customerList;
}

//Set Customer List onto Value Stack
public void setCustomerList(List<Customer> customerList) {
    this.customerList = customerList;
}

public String execute() throws Exception {
    return SUCCESS;
}

public Object getModel() {
    return customer;
}



// Edit customer details, it will retrieve the records based on customerId
//SkipValidation is used to skip the validate()
@SkipValidation
public String getCustomerById() {

    logger.info("** Customer Id to edit ** " + customer.getCustomerId());

    customer = customerDAO.customerById(customer.getCustomerId());

    return SUCCESS;

}

【问题讨论】:

  • 为什么要隐藏id?如果您将值存储在客户端,任何人都可以查看源代码并获取它。您当然可以使用 post 发送结果,但请考虑用户需要为页面添加书签。真正的答案是安全性……这个用户应该能够访问这个客户 ID 吗?如果不是,那么在任何情况下都不应该允许。
  • 是的,用户可以为这样的页面添加书签...但是问题是Update a customer,而URL是**getCustomer**Action?customerId=2...这里有些奇怪:>
  • @AndreaLigios - 场景是,要更新客户,我必须在表单上预先填充他的详细信息。为了获取详细信息,我使用 customerId 查询数据库。
  • @Quaternion - 你问题的第一部分 - 你为什么要隐藏 id?由于查询字符串是可见的,因此用户可以重新触发该操作。所以为了避免同样的情况,我需要隐藏查询字符串。其次,由于我在这里没有使用表单,并且当我尝试将方法作为帖子提供时,流程会尝试在动作类中查找作为帖子的方法。如果我在这里错了,请告诉我。感谢您的回复。
  • 如果你隐藏了URL,但用户在发送请求后多次按F5,它会发送很多相同的请求。还有其他方法(在 SO 上多次讨论)来防止这种情况......

标签: url struts2 tags


【解决方案1】:

一些无序的考虑:

  • 使用不同的Action(仅限execute方法),或者同一个Action的不同Method,执行不同的“动作”;
  • 每个动作/方法的名称应该与执行的操作相匹配并且是不言自明的,例如你应该有一个editCustomer 方法(或动作)来编辑客户和一个@987654322 @方法(或操作)获取客户;
  • 应该使用GET HTTP方法来读取数据,而应该使用POST HTTP方法来发送数据;每个非读取操作应该理想地通过 POST 执行;使用 GET 发送数据是 20 年前诞生并且从未消亡的老坏习惯:/ 使用 POST 的原因是隐藏的 URL、更高的负载能力、发送二进制数据的能力等...

也就是说,http://foo.com/Struts2Example/getCustomerAction?customerId=2 之类的 URL 应该是可见的(例如要添加书签),并且理想情况下应该是美化的(REST 样式,例如 StackOverflow):类似于http://foo.com/Struts2Example/Customer/2/

http://foo.com/Struts2Example/editCustomerAction?customerId=2 之类的 URL 不起作用,因为您没有传递任何其他参数;您知道要编辑的客户 ID,但不知道要更改的数据... 它会变成这样: http://foo.com/Struts2Example/editCustomerAction?customerId=2&amp;name=foo&amp;lastname=bar&amp;age=42,这可行,但如前所述(以及在您的问题中提出的问题)应该被隐藏,并通过 POST 处理。

如果您在页面的source 中打印IDs,那么应该不需要向用户隐藏它们;

您需要做的是确保用户不能将IDs 更改到您指定的范围之外; 如果您在页面中绘制了带有ID {1,2,3} 的客户列表,则必须阻止用户更改ID 并尝试使用ID = 4 更新客户的任何尝试...要实现此目的,只需将ID 列表存储在在填充页面之前session,并根据您的列表检查页面返回的IDs。如果不匹配,则阻止恶意操作。

希望有帮助

【讨论】:

  • 感谢您的宝贵时间和回复。完全同意你的观点,w.r.t 动作/方法名称。其次,由于我在这里没有使用表单,在我的情况下,如何将操作请求作为 POST?在这里感谢您的帮助。
  • 不客气;你为什么不使用表格?为什么你不能添加一个?他们是免费的:)
  • 该场景不需要表单。由于我没有找到任何其他合适的选择,我不妨选择一个表格。也因为它们是免费的;)感谢人们对我的查询的答复。欣赏它!干杯!
  • 不客气。顺便说一句,由于您想 POST 而不是 GET,所以场景(现在)需要一个表单;)
【解决方案2】:

另一种方法是加密用户 ID 并将其发送回 HTML 页面。在客户端维护映射。当您提交请求时,POST 加密值。解密/加密逻辑将在服务器端。 这将增加系统开销,但与安全性相比,这是一个足够好的性能折衷。 另请查看@jcryption.org/info,它在 MIT 和 GPL 许可下。

更简单的解决方案是将其转换为“POST”操作,以便在 HTTP 请求正文中传递值。如果它通过 HTTPS ,它将被加密但是您仍然可以使用 Google 开发人员工具或 IE9 开发人员模式进行用户 ID 查找

【讨论】:

  • 将 cmets 转换为答案。请忽略 cmets。谢谢
  • @user1428716- 感谢您的回答。在这种情况下,由于我没有使用 struts 表单,我该如何实现/将请求转换为 POST?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-23
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-16
相关资源
最近更新 更多