Hi, I am trying to allow anoymous access to a Web API method. I have added "[AbpAllowAnonymous]" to the class and the method but the API throws "500 Internal Server Error" until sign in to the application or pass a valid auth token.
I am using the ASP.NET MVC 5.x, ASP.NET Web API and Angularjs 1.x based Single-Page Application (SPA) solution.
May I have to use [AbpAllowAnonymous] for all methods in the Core project that I reference from the app service method too? I also use repositories in the method.
Thank you very much.
14 Answer(s)
-
0
Hi,
This should work as you expected. You only need to add it to appService method you are requesting. For example, when I add [AbpAllowAnonymous] to GetUsers method of UserAppService, below request returns users.
POST /api/services/app/user/GetUsers HTTP/1.1 Host: localhost:6240 Content-Type: application/json Cache-Control: no-cache Postman-Token: 55995a1b-0401-141b-3e56-3bdc3f3ffe33 {}
Can you share your code ? And, which ABP version do you use ?
-
0
Thank you for your hints. Using it with the GetUsers method works for me too.
I am using Abp.1.0.0.0. There is much info inlucded in the code that should not get public, so I am not able to share it at the moment.
I am not using [AbpAuthorize] and cannot access the method - is that a hint, that something is generally configured wrong? I am getting "500 Internal Server Error" and not "401 Unauthorized".
-
0
Then you can check your Logs.txt file for more detailed error message. It must be under your Web project. Probably there is another problem, maybe we can understand it better with error logs.
-
0
OK, I have checked logs and debugged - and now I am sure that the only problem I hit is that I cannot use repositories to access database. All repositories deliver 0 results. When I sign in to the backend and trigger the method again, than the repositories deliver the results.
Do I have to define anonymous access somewhere else to get the repositories working? Very strange about this behaviour is the fact that the GetUsers method works with repositories too and does not run into problems. I have compared the structure of my own service class and the UserAppService class and cannot find differences.
Thank you!
-
0
Additional info - I have added the _userRoleRepository to my class and I am able to retrieve results anonymously. But where could be the difference between my own repositories and the ABP ones? Thanks!
-
0
Hi,
Do you make any session related filtering or any other operation in your app service method ? You can make a simple test and try to return list of entities in your app service method.
You can use IRepository<MyEntity> _myEntityRepsitory and return
_myEntityRepsitory .GetAllList().MapTo<List<MyEntityDto>>();
And see if this works anonymously or not.
-
0
Thank you - I have already tried this with several of my repositories. They all deliver 0 items until I sign in. No not authorized or error messages just 0 items.
-
0
It seems that it does not work with repositories based on entities that are defined in the project - I have done the following test to check it: I have changed the build in GetUserChatMessages from ChatAppService and changed it to:
[AbpAllowAnonymous] public async Task<ListResultDto<ChatMessageDto>> GetUserChatMessages(GetUserChatMessagesInput input) { //var userId = AbpSession.GetUserId(); //var messages = await _chatMessageRepository.GetAll() // .WhereIf(input.MinMessageId.HasValue, m => m.Id < input.MinMessageId.Value) // .Where(m => m.UserId == userId && m.TargetTenantId == input.TenantId && m.TargetUserId == input.UserId) // .OrderByDescending(m => m.CreationTime) // .Take(50) // .ToListAsync(); var messages = await _chatMessageRepository.GetAll().Where(m=>m.UserId == 2).ToListAsync(); messages.Reverse(); return new ListResultDto<ChatMessageDto>(messages.MapTo<List<ChatMessageDto>>()); }
The result is the same as for my own AppService class - not a single result row for anonymous users. You can call it anonymously, it jumps into the method in debug, you can step through the code until the end of the method but the repository always delivers 0 result rows from database - until you sign in with a user and repeat it - then you get the results you expect.
So where do I have to change what to allow anonymous access to the repositories? Thank you very much.
-
0
Hi,
Thank you for sharing the detailed example. Reason of the problem is, when you call an app service anonymously, AbpSession.TenantId is set to null and only host records with TenantId = null returns from your query.
In order to fix that, we used a header named "Abp.TenantId" in our AspNet Core template, you can see it here <a class="postlink" href="https://github.com/aspnetzero/aspnet-zero-core/blob/8cc457e12a59374133ef90c2aebd6de71738ad07/src/MyCompanyName.AbpZeroTemplate.Web.Core/MultiTenancy/TenantIdAccessor.cs">https://github.com/aspnetzero/aspnet-ze ... ccessor.cs</a>.
It checks tenantId fist and if it is null it tries to find tenantId from header named "Abp.TenantId".
You can change your TenantIdAccessor class like the one above. Then you need to send Abp.TenantId header while requesting api method anonymously.
We will also add this functionality to ABP. You can delete your code when it is implemented and you update ABP nuget pacakges in the future.
-
0
Thank you very much - that was the problem!
Is my code ok or is there a better way to solve it?
Solution.Web.MultiTenancy.TenantIdAccessor.cs:
public void SetCurrentTenantId() { var tenancyName = _tenancyNameFinder.Value.GetCurrentTenancyNameOrNull(); CurrentTenantId = GetVerifiedTenantIdOrNull(); } private int? GetVerifiedTenantIdOrNull() { var tenantIdFromClient = GetFromHeaderOrNull(); if (tenantIdFromClient != null) { return _tenantCache.GetOrNull(tenantIdFromClient.Value)?.Id; } return null; } private int? GetFromHeaderOrNull() { if (HttpContext.Current == null) { return null; } if(HttpContext.Current.Request.Headers.GetValues("Abp.TenantId") == null) { return null; } var header = HttpContext.Current.Request.Headers.GetValues("Abp.TenantId").GetValue(0).ToString(); if (string.IsNullOrWhiteSpace(header)) { return null; } int tenantId; return int.TryParse(header, out tenantId) ? (int?)tenantId : null; }
-
0
Your code seems fine.
-
0
Perfect - thank you very much.
-
0
Could you please give me a hint if there is a way to protect the whole Web API by making it accessible only to a defined set of IP addresses? Thank you very much for your great support!
-
0
Hi,
This issue might help you <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/issues/987">https://github.com/aspnetboilerplate/as ... issues/987</a>.