5

我有一种简单(可能是粗略)的方式来审核我正在构建的博客上的评论。这是一个学习/有趣的项目,所以我正在尽我所能自己来熟悉一些不同的技术。我想知道我的逻辑是否有任何漏洞,或者可能是我正在做的更好的实现。我将允许在网站上发表匿名评论,但我想对我认为不合适的任何内容进行审核。以下是我的做法:

我的模型使用 EF 代码优先方法:

public class Comment
{
    public int Id { get; set; }
    public bool Moderated { get; set; }
    public string DisplayName { get; set; }
    public string Email { get; set; }
    public DateTime DateCreated { get; set; }
    public string Content { get; set; }
    public int PostId { get; set; }
    public Post Post { get; set; }
}

标准的东西在这里。然后我创建了一个 ViewModel 来显示博客文章的详细信息以及与之相关的所有评论,如下所示:

public class PostCommentViewModel
{
    public Post Post { get; set; }
    public List<Comment> Comment { get; set; }

    public PostCommentViewModel(int postId)
    {
        var db = new BlogContext();

        Post = db.Posts.First(x => x.Id == postId);
        var query = from x in db.Comments where x.PostId == postId && x.Moderated == true select x;

        Comment = query.ToList();
    }
}

对于评论,这只是抓取与 PostId 相关且已审核的评论(即我已经能够查看它们)

对于显示的视图,我只使用基本脚手架模板:

public ActionResult Details(int id = 0)
    {
        var viewModel = new PostCommentViewModel(id);
        return View(viewModel);
    }

该cshtml:

@model CodeFirstBlog.ViewModels.PostCommentViewModel


<fieldset>
<legend>PostCommentViewModel</legend>
@Html.DisplayFor(x => x.Post.Title)
<br />
@Html.DisplayFor(x => x.Post.Content)
<br />
@Html.DisplayFor(x => x.Post.CreatedDate)
<hr />    
@foreach(var comment in Model.Comment)
{
    @Html.DisplayFor(x => comment.Content)
    <br />
    @Html.DisplayFor(x => comment.DateCreated)
    <br />
    @Html.DisplayFor(x => comment.DisplayName)
    <br />
    @Html.DisplayFor(x => comment.Email)
    <br />
    <hr />
}

</fieldset>
@Html.ActionLink("Add Comment", "AddComment", new { id = Model.Post.Id} )

这是控制器中的 AddComment

public ActionResult AddComment(int id = 0)
    {
        return View();
    }

    [HttpPost]
    public ActionResult AddComment(Comment comment, int id)
    {
        if (ModelState.IsValid)
        {
            comment.PostId = id;
            db.Comments.Add(comment);
            db.SaveChanges();
            return RedirectToAction("Details", "Blog", new { id = id });
        }
        return RedirectToAction("Details", "Blog", new { id = id });
    }

因此,当我添加评论时,Moderated 默认为 false,因此评论不会立即显示。现在,如果管理员登录,他可以转到 ViewModeration 视图,该视图只返回等待批准的所有评论的列表:

public ActionResult ViewModeration()
    {
        var comments = from x in db.Comments where x.Moderated == false select x;
        return View(comments);
    }

如果他单击批准按钮,它将在控制器中执行:

 public ActionResult ApproveComment(int id)
    {
        Comment c = (from x in db.Comments
                     where x.Id == id
                     select x).First();
        c.Moderated = true;
        db.SaveChanges();
        return RedirectToAction("ViewModeration");
    }

我真正想知道的是:

  1. 此实现中是否存在任何漏洞,例如知情用户能否覆盖回发中的审核值?
  2. 有没有更简单,或者更优雅的解决方案可以遵循?同样,我不想使用任何预先构建的东西。这个项目的重点是学习东西。
4

2 回答 2

4

到目前为止,该模型似乎推迟了,所以我将这样回答这个问题:

此实现中是否存在任何漏洞,例如知情用户能否覆盖回发中的审核值?

是的。我没有根据您发送的任何 FORM 代码,但我假设您正在通过 post 值创建评论并直接保存到数据库。这可能很糟糕。您最好只从用户那里获取您需要的值,然后在控制器中填写其余的值:

public ActionResult AddComment(Comment comment, int id)
{
    if (ModelState.IsValid)
    {
        // NEW
        comment.Moderated = false;

        comment.PostId = id;
        db.Comments.Add(comment);
        db.SaveChanges();
        return RedirectToAction("Details", "Blog", new { id = id });
    }
    return RedirectToAction("Details", "Blog", new { id = id });
}

有没有更简单,或者更优雅的解决方案可以遵循?同样,我不想使用任何预先构建的东西。这个项目的重点是学习东西。

如前所述,到目前为止,这看起来不错。但是,出于可重用性和测试目的,我可能会在不同的类中获取数据库操作,例如服务或存储库。

因此,代码将如下所示:

public ActionResult AddComment(Comment comment, int id)
{
    if (ModelState.IsValid)
    {
        CommentService.Save(comment);
        return RedirectToAction("Details", "Blog", new { id = id });
    }
    return RedirectToAction("Details", "Blog", new { id = id });
}

这不是一个大的变化,但如果你想重用这段代码,它会让你在以后获得更多的灵活性。

至于您的 PostCommentViewModel 类,我没有在 ViewModels 中执行任何操作,尤其是在构造函数中。您应该使用 ViewModels 的方式是将数据绑定到它上,而不是让 ViewModel 完成这项工作。无论如何,您都可以从中获取数据,ViewModel 仅代表需要显示的结构。因此,从那里获取代码,并将其放入服务中(即:CommentService)。

于 2012-06-29T17:17:50.433 回答
2

第一个问题的答案是肯定的,知道的用户可以设置Moderatedvalue。不久前,类似的事情发生在 GitHub 上。有关完整说明,请参阅此帖子。简短的解释是,用户可以在 Chrome 开发者工具中修改表单数据,并Moderated在发布之前在模型上设置属性。

要回答您的第二个问题,我可以看到两个选项(如果您知道更多,请发表评论)

1)您可以调用并仅指定应更新的属性,而不是DefaultModelBinder将值绑定到您的模型。例如CommentTryUpdateModel

public ActionResult AddComment(int id)
{
    if (ModelState.IsValid)
    {
        Comment comment = new Comment();
        TryUpdateModel(comment, new[] { "Email ", "DateCreated", "Content", "etc" });
        comment.PostId = id;
        db.Comments.Add(comment);
        ...
    }
    ...
}

2)更好的选择,恕我直言,是创建一个甚至不包含该Moderated属性的单独模型类,并将该模型用于用户评论。您可以将现有Comment模型用于仅管理员可访问的操作上的管理目的。

于 2012-06-29T17:15:42.463 回答