dimanche 4 décembre 2022

Custom Attribute For Class Library Classes and Functions in C#

I'm developing 3rd party API connector bridge in class library NOT in ASP.NET.

User Levels

API has 3 user levels, lets say:

  • UserGoer
  • UserDoer
  • UserMaker

Service Restriction

Each API operation can work with one or multiple user level roles. For example, lets assume operations and reachable user levels as follows;

  • JokerService (reachable by UserGoer, UserMaker)
  • PokerService (reachable by UserGoer, UserDoer)
  • MokerService (reachable by UserGoer, UserDoer, UserMaker)

If UserDoer requests for JokerService, API returns bad request. JokerService is only reachable for UserGoer and UserMaker. So, I want to restrict and throw an exception.

User Token Structure

public interface IToken
{
    string AccessToken { get; set; }

    string RefreshToken { get; set; }
}

public class AuthenticationToken : IToken
{
    [JsonProperty("access_token")]
    public string AccessToken { get; set; }

    [JsonProperty("refresh_token")]
    public string RefreshToken { get; set; }
}


public class UserGoerAuthenticationToken : AuthenticationToken
{
}

public class UserDoerAuthenticationToken : AuthenticationToken
{
}

public class UserMakerAuthenticationToken : AuthenticationToken
{
}

Enum

public enum TokenType
{
    Undefined = 0,
    UserGoer = 1,
    UserDoer = 2,
    UserMaker = 3
}

Customized Authentication Attribute

public class AuthenticationFilter : Attribute
{
    public TokenType[] TokenTypes { get; private set; }

    public AuthenticationFilter(params TokenType[] TokenTypes)
    {
        this.TokenTypes = TokenTypes;
    }
}

Example Service

[AuthenticationFilter(TokenType.UserGoer, TokenType.UserMaker)]
internal class JokerService : BaseService<JokerEntity>
{
    public JokerService(IToken AuthenticationToken) : base(AuthenticationToken)
    {
        var tokenTypes = 
              (typeof(JokerService).GetCustomAttributes(true)[0] as AuthenticationFilter)
              .TokenTypes;

        bool throwExceptionFlag = true;
        foreach (var item in tokenTypes)
        {
            // Check AuthenticationToken is UserGoer or UserMaker by StartsWith function
            if (AuthenticationToken.GetType().Name.StartsWith(item.ToString()))
            {
                throwExceptionFlag = false;
                break;
            }
        }

        if (throwExceptionFlag)
            throw new Exception("Invalid Authentication Token");
    }

    public JokerEntity Create(RequestModel<JokerEntity> model) => base.Create(model);

    public JokerEntity Update(RequestModel<JokerEntity> model) => base.Update(model);

    public JokerEntity Get(RequestModel<JokerEntity> model) => base.Get(model);

    public List<JokerEntity> List(RequestModel<JokerEntity> model) => base.List(model);
}

In summary, JokerService can be executable by UserGoer and UserMaker. UserDoer has no permission for this service.

As you see the the usage of AuthenticationFilter attribute, I'm getting custom attributes in the constructor, because i want to know what IToken is. If there is an irrelevant "User Authentication Token" type that is passed as parameter (IToken), program should be throw an exception.

This is my solution, do you think is there any best practice for my problem?

Thank you for your help.

Aucun commentaire:

Enregistrer un commentaire