Browse Source

blog module permission improvements

pull/441/head
Yunus Emre Kalkan 8 years ago
parent
commit
13237ee779
  1. 8575
      modules/blogging/app/Volo.BloggingTestApp/Logs/logs.txt
  2. 18
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/BloggingApplicationModule.cs
  3. 4
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Blogs/BlogAppService.cs
  4. 34
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Comments/CommentAppService.cs
  5. 61
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Comments/CommentAuthorizationHandler.cs
  6. 13
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/CommonOperations.cs
  7. 6
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs
  8. 61
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAuthorizationHandler.cs
  9. 95
      modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Detail.cshtml
  10. 2
      modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/detail.js

8575
modules/blogging/app/Volo.BloggingTestApp/Logs/logs.txt

File diff suppressed because it is too large

18
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/BloggingApplicationModule.cs

@ -1,7 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
using Volo.Blogging.Comments;
using Volo.Blogging.Posts;
namespace Volo.Blogging
{
@ -18,6 +21,19 @@ namespace Volo.Blogging
{
options.AddProfile<BloggingApplicationAutoMapperProfile>(validate: true);
});
context.Services.Configure<AuthorizationOptions>(options =>
{
//TODO: Rename UpdatePolicy/DeletePolicy since it's candidate to conflicts with other modules!
options.AddPolicy("BloggingUpdatePolicy", policy => policy.Requirements.Add(CommonOperations.Update));
options.AddPolicy("BloggingDeletePolicy", policy => policy.Requirements.Add(CommonOperations.Delete));
});
context.Services.AddSingleton<IAuthorizationHandler, CommentAuthorizationHandler>();
context.Services.AddSingleton<IAuthorizationHandler, PostAuthorizationHandler>();
}
}
}

4
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Blogs/BlogAppService.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
@ -56,6 +57,7 @@ namespace Volo.Blogging.Blogs
return ObjectMapper.Map<Blog, BlogDto>(blog);
}
[Authorize(BloggingPermissions.Blogs.Create)]
public async Task<BlogDto> Create(CreateBlogDto input)
{
var newBlog = await _blogRepository.InsertAsync(new Blog(GuidGenerator.Create(), input.Name, input.ShortName){Description = input.Description});
@ -63,6 +65,7 @@ namespace Volo.Blogging.Blogs
return ObjectMapper.Map<Blog, BlogDto>(newBlog);
}
[Authorize(BloggingPermissions.Blogs.Update)]
public async Task<BlogDto> Update(Guid id, UpdateBlogDto input)
{
var blog = await _blogRepository.GetAsync(id);
@ -74,6 +77,7 @@ namespace Volo.Blogging.Blogs
return ObjectMapper.Map<Blog, BlogDto>(blog);
}
[Authorize(BloggingPermissions.Blogs.Delete)]
public async Task Delete(Guid id)
{
await _blogRepository.DeleteAsync(id);

34
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Comments/CommentAppService.cs

@ -12,7 +12,6 @@ using Volo.Blogging.Users;
namespace Volo.Blogging.Comments
{
// [Authorize(BloggingPermissions.Comments.Default)]
public class CommentAppService : ApplicationService, ICommentAppService
{
protected IBlogUserLookupService UserLookupService;
@ -96,22 +95,8 @@ namespace Volo.Blogging.Comments
{
var comment = await _commentRepository.GetAsync(id);
if (CurrentUser.Id != comment.CreatorId)
{
return await UpdateAsAdminAsync(id, comment, input);
}
return await UpdateCommentAsync(id, comment, input);
}
await AuthorizationService.CheckAsync(comment, CommonOperations.Update);
[Authorize(BloggingPermissions.Comments.Update)]
private async Task<CommentWithDetailsDto> UpdateAsAdminAsync(Guid id, Comment comment, UpdateCommentDto input)
{
return await UpdateCommentAsync(id, comment, input);
}
private async Task<CommentWithDetailsDto> UpdateCommentAsync(Guid id, Comment comment, UpdateCommentDto input)
{
comment.SetText(input.Text);
comment = await _commentRepository.UpdateAsync(comment);
@ -123,23 +108,8 @@ namespace Volo.Blogging.Comments
{
var comment = await _commentRepository.GetAsync(id);
if (CurrentUser.Id != comment.CreatorId)
{
await DeleteAsAdminAsync(id);
return;
}
await DeleteCommentAsync(id);
}
await AuthorizationService.CheckAsync(comment, CommonOperations.Delete);
[Authorize(BloggingPermissions.Comments.Delete)]
private async Task DeleteAsAdminAsync(Guid id)
{
await DeleteCommentAsync(id);
}
private async Task DeleteCommentAsync(Guid id)
{
await _commentRepository.DeleteAsync(id);
var replies = await _commentRepository.GetRepliesOfComment(id);

61
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Comments/CommentAuthorizationHandler.cs

@ -0,0 +1,61 @@
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Blogging.Comments
{
public class CommentAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Comment>
{
private readonly IPermissionChecker _permissionChecker;
public CommentAuthorizationHandler(IPermissionChecker permissionChecker)
{
_permissionChecker = permissionChecker;
}
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Comment resource)
{
if (requirement.Name == CommonOperations.Delete.Name && await HasDeletePermission(context, resource))
{
context.Succeed(requirement);
return;
}
if (requirement.Name == CommonOperations.Update.Name && await HasUpdatePermission(context, resource))
{
context.Succeed(requirement);
return;
}
}
private async Task<bool> HasDeletePermission(AuthorizationHandlerContext context, Comment resource)
{
if (await _permissionChecker.IsGrantedAsync(context.User, BloggingPermissions.Comments.Delete))
{
return true;
}
return false;
}
private async Task<bool> HasUpdatePermission(AuthorizationHandlerContext context, Comment resource)
{
if (resource.CreatorId != null && resource.CreatorId == context.User.FindUserId())
{
return true;
}
if (await _permissionChecker.IsGrantedAsync(context.User, BloggingPermissions.Comments.Update))
{
return true;
}
return false;
}
}
}

13
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/CommonOperations.cs

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace Volo.Blogging
{
public static class CommonOperations
{
public static OperationAuthorizationRequirement Update = new OperationAuthorizationRequirement { Name = nameof(Update) };
public static OperationAuthorizationRequirement Delete = new OperationAuthorizationRequirement { Name = nameof(Delete) };
}
}

6
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs

@ -134,6 +134,10 @@ namespace Volo.Blogging.Posts
public async Task DeleteAsync(Guid id)
{
var post = await _postRepository.GetAsync(id);
await AuthorizationService.CheckAsync(post, CommonOperations.Delete);
var tags = await GetTagsOfPost(id);
_tagRepository.DecreaseUsageCountOfTags(tags.Select(t=>t.Id).ToList());
_postTagRepository.DeleteOfPost(id);
@ -147,6 +151,8 @@ namespace Volo.Blogging.Posts
{
var post = await _postRepository.GetAsync(id);
await AuthorizationService.CheckAsync(post, CommonOperations.Update);
post.SetTitle(input.Title);
post.SetUrl(input.Url);
post.Content = input.Content;

61
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAuthorizationHandler.cs

@ -0,0 +1,61 @@
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Blogging.Posts
{
public class PostAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Post>
{
private readonly IPermissionChecker _permissionChecker;
public PostAuthorizationHandler(IPermissionChecker permissionChecker)
{
_permissionChecker = permissionChecker;
}
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Post resource)
{
if (requirement.Name == CommonOperations.Delete.Name && await HasDeletePermission(context, resource))
{
context.Succeed(requirement);
return;
}
if (requirement.Name == CommonOperations.Update.Name && await HasUpdatePermission(context, resource))
{
context.Succeed(requirement);
return;
}
}
private async Task<bool> HasDeletePermission(AuthorizationHandlerContext context, Post resource)
{
if (await _permissionChecker.IsGrantedAsync(context.User, BloggingPermissions.Comments.Delete))
{
return true;
}
return false;
}
private async Task<bool> HasUpdatePermission(AuthorizationHandlerContext context, Post resource)
{
if (resource.CreatorId != null && resource.CreatorId == context.User.FindUserId())
{
return true;
}
if (await _permissionChecker.IsGrantedAsync(context.User, BloggingPermissions.Comments.Update))
{
return true;
}
return false;
}
}
}

95
modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Detail.cshtml

@ -186,10 +186,14 @@
@commentWithRepliesDto.Comment.Text
</p>
<div class="comment-buttons font-75 bg-light">
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Create))
{
<a href="#" class="tag replyLink" data-relpyid="@commentWithRepliesDto.Comment.Id">
<i class="fa fa-reply" aria-hidden="true"></i> @L["Reply"]
</a>
}
<a href="#" class="tag replyLink" data-relpyid="@commentWithRepliesDto.Comment.Id">
<i class="fa fa-reply" aria-hidden="true"></i> @L["Reply"]
</a>
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Delete))
{
<span class="seperator">|</span>
@ -206,27 +210,29 @@
</a>
}
</div>
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Create))
{
<div class="comment-form mt-4 replyForm">
<div class="clearfix bg-light p-4">
<h3 class="mt-0">
@L["ReplyTo"]
@(commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName)
</h3>
<div>
<form method="post">
<input name="postId" value="@Model.Post.Id" hidden/>
<input name="repliedCommentId" value="@commentWithRepliesDto.Comment.Id" hidden/>
<div class="comment-form mt-4 replyForm">
<div class="clearfix bg-light p-4">
<h3 class="mt-0">
@L["ReplyTo"]
@(commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName)
</h3>
<div>
<form method="post">
<input name="postId" value="@Model.Post.Id" hidden />
<input name="repliedCommentId" value="@commentWithRepliesDto.Comment.Id" hidden />
<div class="form-group">
<textarea class="form-control no-border" name="text" id="textBoxId" rows="4"></textarea>
</div>
<abp-button button-type="Primary" class="btn-rounded float-right" type="submit" text="@L["Comment"].Value" />
</form>
<div class="form-group">
<textarea class="form-control no-border" name="text" id="textBoxId" rows="4"></textarea>
</div>
<abp-button button-type="Primary" class="btn-rounded float-right" type="submit" text="@L["Comment"].Value"/>
</form>
</div>
</div>
</div>
</div>
}
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId))
{
<div class="comment-form mt-4 editForm">
@ -257,10 +263,13 @@
@reply.Text
</p>
<div class="comment-buttons font-75 bg-light">
<a href="#" class="tag replyLink" data-relpyid="@commentWithRepliesDto.Comment.Id">
<i class="fa fa-reply" aria-hidden="true"></i> @L["Reply"]
</a>
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Create))
{
<a href="#" class="tag replyLink" data-relpyid="@commentWithRepliesDto.Comment.Id">
<i class="fa fa-reply" aria-hidden="true"></i> @L["Reply"]
</a>
}
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Delete) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId))
{
<span class="seperator">|</span>
@ -278,25 +287,27 @@
}
</div>
<div class="comment-form mt-4 replyForm">
<div class="clearfix bg-light p-4">
<h3 class="mt-0">
@L["ReplyTo"]
@(commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName)
</h3>
<div>
<form method="post">
<input name="postId" value="@Model.Post.Id" hidden />
<input name="repliedCommentId" value="@commentWithRepliesDto.Comment.Id" hidden />
<div class="form-group">
<textarea class="form-control no-border" name="text" id="textBoxId" rows="4"></textarea>
</div>
<abp-button button-type="Primary" class="btn-rounded float-right" type="submit" text="@L["Submit"].Value" />
</form>
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Create))
{
<div class="comment-form mt-4 replyForm">
<div class="clearfix bg-light p-4">
<h3 class="mt-0">
@L["ReplyTo"]
@(commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName)
</h3>
<div>
<form method="post">
<input name="postId" value="@Model.Post.Id" hidden />
<input name="repliedCommentId" value="@commentWithRepliesDto.Comment.Id" hidden />
<div class="form-group">
<textarea class="form-control no-border" name="text" id="textBoxId" rows="4"></textarea>
</div>
<abp-button button-type="Primary" class="btn-rounded float-right" type="submit" text="@L["Submit"].Value" />
</form>
</div>
</div>
</div>
</div>
}
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId))
{
<div class="comment-form mt-4 editForm">

2
modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/detail.js

@ -52,7 +52,7 @@
if (deleteCommentId != '' && deleteCommentId !== undefined) {
abp.message.confirm(
l('CommentDeletionWarningMessage'), // TODO: localize
l('Are you sure?)',
l('Are you sure?'),
function(isConfirmed) {
if (isConfirmed) {
$.ajax({

Loading…
Cancel
Save