Base solution for your next web application
Starts in:
01 DAYS
01 HRS
01 MIN
01 SEC
Open Closed

Anonymous Web API method #2295


User avatar
0
jamsecgmbh created

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)
  • User Avatar
    0
    ismcagdas created
    Support Team

    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 ?

  • User Avatar
    0
    jamsecgmbh created

    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".

  • User Avatar
    0
    ismcagdas created
    Support Team

    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.

  • User Avatar
    0
    jamsecgmbh created

    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!

  • User Avatar
    0
    jamsecgmbh created

    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!

  • User Avatar
    0
    ismcagdas created
    Support Team

    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.

  • User Avatar
    0
    jamsecgmbh created

    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.

  • User Avatar
    0
    jamsecgmbh created

    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.

  • User Avatar
    0
    ismcagdas created
    Support Team

    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.

  • User Avatar
    0
    jamsecgmbh created

    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;
            }
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Your code seems fine.

  • User Avatar
    0
    jamsecgmbh created

    Perfect - thank you very much.

  • User Avatar
    0
    jamsecgmbh created

    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!

  • User Avatar
    0
    ismcagdas created
    Support Team

    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>.