Asp.Net Core 3.1 learning 4. JWT based token verification and Swagger use in Web Api

Posted by presence on Tue, 28 Apr 2020 07:06:22 +0200

1. Initial JWT

1.1 JWT principle

JWT (JSON Web Token) is the most popular cross domain authentication solution at present. Its advantage lies in that the server does not need to store tokens for distributed development, and provides data for the APP for the project of front-end and back-end separation. The items of the token generated by login can be completely independent of other items. When the user accesses the login interface, a token will be returned, and then the token will be brought to access other interfaces that need to be logged in. If the token is valid, we think the user is logged in normally. Then we can take some information from the token for operation. Of course, these carried information can be passed through other additional fields, but if it is passed by token, there is no need to add other fields.

JWT declaration is generally used to transfer the authenticated user identity information between identity provider and service provider, so as to obtain resources from resource server, and add some additional declaration information necessary for other business logic. The token can also be directly used for authentication or encryption.

1.2 JWT structure

JWT is made up of three pieces of information. The JWT string is made up of these three pieces of information text with. Link. Like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbklEIjoiYWRtaW4iLCJuYmYiOjE1ODc4OTE2OTMsImV4cCI6MTU4NzkyNzY5MywiaXNzIjoiV1lZIiwiYXVkIjoiRXZlcnlUZXN0T25lIn0.-snenNVHrrKq9obN8FzKe0t99ok6FUm5pHv-P_eYc30

In the first part, we call it header: declaration type, here is jwt; the algorithm of declaration encryption usually uses HMAC SHA256 directly

{
  'typ': 'JWT',
  'alg': 'HS256'
}

 

In the second part, we call it payload

iss: Token publisher

exp: expiration time minutes

sub: subject

aud: Token receiver

nbf: not available until

iat: release time

jti: JWT ID is used to identify the JWT

In addition to the above default fields, we can also customize private fields, as shown in the following example:

{

"sub": "1234567890",

"name": "wyy",

"admin": true

}

 

The third part is the signature: this part needs the string composed of base64 encrypted header and base64 encrypted payload. The string is then encrypted by adding salt secret in the encryption method declared in the header, and then constitutes the third part of jwt.

2. Generate Token

2.1 establishment of project

In VS2019, create a new Core Api program, select 3.1 for Core, and then add a Jwt folder help class on the project, create a new interface ITokenHelper, class: TokenHelper inherits ITokenHelper, class JWTConfig, class TnToken

JWTConfig: used to save and read jwt related configuration

 

/// <summary>
    /// To configure token Generate information
    /// </summary>
    public class JWTConfig
    {
        /// <summary>
        /// Token Publisher
        /// </summary>
        public string Issuer { get; set; }
        /// <summary>
        /// oken recipient
        /// </summary>
        public string Audience { get; set; }
        /// <summary>
        /// Secret key
        /// </summary>
        public string IssuerSigningKey { get; set; }
        /// <summary>
        /// Expiration time
        /// </summary>
        public int AccessTokenExpiresMinutes { get; set; }
    }

TnToken: a class for storing Token and expiration time

/// <summary>
    /// Deposit Token Class with expiration time
    /// </summary>
    public class TnToken
    {
        /// <summary>
        /// token
        /// </summary>
        public string TokenStr { get; set; }
        /// <summary>
        /// Expiration time
        /// </summary>
        public DateTime Expires { get; set; }
    }

 

Itoken helper interface: the interface of token tool class. It is convenient to use dependency injection. It is very simple to provide two common methods

/// <summary>
    /// token The interface of tool class is convenient to use dependency injection. It is very simple to provide two common methods
    /// </summary>
    public interface ITokenHelper
    {
        /// <summary>
        /// Provides load generation through reflection based on an object token
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="user"></param>
        /// <returns></returns>
        TnToken CreateToken<T>(T user) where T : class;
        /// <summary>
        /// Provide load generation based on key value pair token
        /// </summary>
        /// <param name="keyValuePairs"></param>
        /// <returns></returns>
        TnToken CreateToken(Dictionary<string, string> keyValuePairs);
    }

 

TokenHelper: implementation class

/// <summary>
    /// Token Generating class
    /// </summary>
    public class TokenHelper : ITokenHelper
    {
        private readonly IOptions<JWTConfig> _options;
        public TokenHelper(IOptions<JWTConfig> options)
        {
            _options = options;
        }

        /// <summary>
        /// Provides load generation through reflection based on an object token
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="user"></param>
        /// <returns></returns>
        public TnToken CreateToken<T>(T user) where T : class
        {
            //Load part carried, similar to a key value pair
            List<Claim> claims = new List<Claim>();
            //Here we use the reflex model Data to it
            foreach (var item in user.GetType().GetProperties())
            {
                object obj = item.GetValue(user);
                string value = "";
                if (obj != null)
                    value = obj.ToString();

                claims.Add(new Claim(item.Name, value));
            }
            //Establish token
            return CreateToken(claims);
        }

        /// <summary>
        /// Provide load generation based on key value pair token
        /// </summary>
        /// <param name="keyValuePairs"></param>
        /// <returns></returns>
        public TnToken CreateToken(Dictionary<string, string> keyValuePairs)
        {
            //Load part carried, similar to a key value pair
            List<Claim> claims = new List<Claim>();
            //Here we provide data to it through key value pairs
            foreach (var item in keyValuePairs)
            {
                claims.Add(new Claim(item.Key, item.Value));
            }
            //Establish token
            return CreateTokenString(claims);
        }
        /// <summary>
        /// generate token
        /// </summary>
        /// <param name="claims">List Of Claim object</param>
        /// <returns></returns>
        private TnToken CreateTokenString(List<Claim> claims)
        {
            var now = DateTime.Now;
            var expires = now.Add(TimeSpan.FromMinutes(_options.Value.AccessTokenExpiresMinutes));
            var token = new JwtSecurityToken(
                issuer: _options.Value.Issuer,//Token Publisher
                audience: _options.Value.Audience,//Token recipient
                claims: claims,//Load carried
                notBefore: now,//current time  token Generation time
                expires: expires,//Expiration time
                signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256));
            return new TnToken { TokenStr = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires };
        }

    }

2.2. Configure jwt in Startup:

In ConfigureServices:

#region jwt To configure
            services.AddTransient<ITokenHelper, TokenHelper>();
            //Read configuration file configuration jwt Related configuration
            services.Configure<JWTConfig>(Configuration.GetSection("JWTConfig"));
            //Enable JWT
            services.AddAuthentication(Options =>
            {
                Options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                Options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).
            AddJwtBearer();#endregion

 

JwtBearerDefaults.AuthenticationScheme and AddJwtBearer(); download the two dependencies. Or NuGet installation

In app settings, simply configure the following jwt related information:

 "JWTConfig": {
        "Issuer": "WYY", //Token publisher
        "Audience": "EveryTestOne", //Token receiver
        "IssuerSigningKey": "WYY&YL889455200Sily", //The secret key can build the server approved token; the signature secret key length is at least 16
        "AccessTokenExpiresMinutes": "600" //Expiration time minutes
    },

 

To enable authentication Middleware in Configure:

//Enabling authentication middleware should be written before authorizing UseAuthorization()
app.UseAuthentication();

2.3. A simple login to obtain token

Create a new api name LoginTest in the Controllers folder

[EnableCors("AllowCors")]
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class LoginTestController : ControllerBase
    {
        private readonly ITokenHelper tokenHelper = null;
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="_tokenHelper"></param>
        public LoginTestController(ITokenHelper _tokenHelper)
        {
            tokenHelper = _tokenHelper;
        }
        /// <summary>
        /// Login test
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
         [HttpPost]
        public ReturnModel Login([FromBody]UserDto user)
        {
            var ret = new ReturnModel();
            try
            {
                if (string.IsNullOrWhiteSpace(user.LoginID) || string.IsNullOrWhiteSpace(user.Password))
                {
                    ret.Code = 201;
                    ret.Msg = "User name and password cannot be empty";
                    return ret;
                }
                //I didn't write the login operation || Assuming successful login
                if (1 == 1)
                {
                    Dictionary<string, string> keyValuePairs = new Dictionary<string, string>
                    {
                        { "loginID", user.LoginID }
                    };
                    ret.Code = 200;
                    ret.Msg = "Login successful";
                    ret.TnToken= tokenHelper.CreateToken(keyValuePairs);
                }
            }
            catch(Exception ex)
            {
                ret.Code = 500;
                ret.Msg = "Login failed:"+ex.Message;
            }
            return ret;
        }
    }

 

UserDto receive class

/// <summary>
    /// Login Class Dto
    /// </summary>
    public class UserDto
    {
        /// <summary>
        /// user name
        /// </summary>
        public string LoginID { get; set; }
        /// <summary>
        /// Password
        /// </summary>
        public string Password { get; set; }
    }

 

ReturnModel is just a unified interface return format standard encapsulated by myself

/// <summary>
    /// Return class
    /// </summary>
    public class ReturnModel
    {
        /// <summary>
        /// Return code
        /// </summary>
        public int Code { get; set; }
        /// <summary>
        /// news
        /// </summary>
        public string Msg { get; set; }
        /// <summary>
        /// data
        /// </summary>
        public object Data { get; set; }
        /// <summary>
        /// Token information
        /// </summary>
        public TnToken TnToken { get; set; }
    }

 

I won't mention it here after the last cross domain article

2.4. Front end obtains token

I use a traditional MVC startup page

<input type="hidden" id="tokenValue" name="tokenValue" value="" />
<br /><br /><br />
<span>Token:</span><div id="txtval"></div><br />
<span>term of validity:</span><div id="txtvalTime"></div><br />

<div>
    <input type="button" value="Obtain Token" onclick="getToken()" /><br /><br /><br />
</div>
<script src="~/Scripts/jquery-3.3.1.js"></script>
<script type="text/javascript">
    //Obtain token
    function getToken() {
        var data = JSON.stringify({ LoginID: "admin", Password: "admin888" });
        $.ajax({
            type: "post",
            url: "https://localhost:44331/api/LoginTest/Login",
            dataType: "json",
            async: true,
            data: data,
            contentType: 'application/json',
            success: function (data) {
                console.log(data);
                $("#txtval").html(data.tnToken.tokenStr);
                $("#txtvalTime").html(new Date(data.tnToken.expires).Format("yyyy-MM-dd hh:mm"));
                $("#tokenValue").val(data.tnToken.tokenStr);

            },
            error: function (data) {
                console.log("error" + data);
            }
        });
    }
    Date.prototype.Format = function (fmt) { //author: zhengsh 2016-9-5
        var o = {
            "M+": this.getMonth() + 1, //Month
            "d+": this.getDate(), //day
            "h+": this.getHours(), //hour
            "m+": this.getMinutes(), //branch
            "s+": this.getSeconds(), //second
            "q+": Math.floor((this.getMonth() + 3) / 3), //quarter
            "S": this.getMilliseconds() //Millisecond
        };
        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
            if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
    }
</script>

 

Start Api and MVC

 

Decoding in JWT pipe network

3. Verify the token passed by the front end

Now let's talk about how to verify the jwt delivered by the foreground. In fact, it's very simple. The most important thing is to verify the validity and expiration of the token. Add two methods of validation to the interface ITokenHelper. Implementation in TokenHelper

Add to itoken helper

/// <summary>
        /// Token Verification
        /// </summary>
        /// <param name="encodeJwt">token</param>
        /// <param name="validatePayLoad">Customize various types of validation; whether to include that declaration, or the declared value</param>
        /// <returns></returns>
        bool ValiToken(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad = null);
        /// <summary>
        /// With return status Token Verification
        /// </summary>
        /// <param name="encodeJwt">token</param>
        /// <param name="validatePayLoad">Customize various types of validation; whether to include that declaration, or the declared value</param>
        /// <param name="action"></param>
        /// <returns></returns>
        TokenType ValiTokenState(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad, Action<Dictionary<string, string>> action);

 

 

 

Add in TokenHelper

/// <summary>
        /// Verify the validity of the authentication signature
        /// </summary>
        /// <param name="encodeJwt"></param>
        /// <param name="validatePayLoad">Custom validations; whether to include that statement, or the value of the statement, </param>
        public bool ValiToken(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad = null)
        {
            var success = true;
            var jwtArr = encodeJwt.Split('.');
            if (jwtArr.Length < 3)//Data format is not direct pass
            {
                return false;
            }
            var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0]));
            var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));
            //Signature secret key extracted from configuration file
            var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(_options.Value.IssuerSigningKey));
            //Verify whether the signature is correct (take out the signature part passed by the user and match the signature generated by the server)
            success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))));
            if (!success)
            {
                return success;//Signature incorrect return directly
            }

            //Second, verify whether it is within the validity period (it should also be necessary)
            var now = ToUnixEpochDate(DateTime.UtcNow);
            success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()));

            //No need for custom authentication, no transfer or transfer null that will do
            if (validatePayLoad == null)
                return true;

            //And then carry out custom verification
            success = success && validatePayLoad(payLoad);

            return success;
        }
        /// <summary>
        /// Time conversion
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        private long ToUnixEpochDate(DateTime date)
        {
            return (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="encodeJwt"></param>
        /// <param name="validatePayLoad"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public TokenType ValiTokenState(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad, Action<Dictionary<string, string>> action)
        {
            var jwtArr = encodeJwt.Split('.');
            if (jwtArr.Length < 3)//Data format is not direct pass
            {
                return TokenType.Fail;
            }
            var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0]));
            var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));
            var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(_options.Value.IssuerSigningKey));
            //Verify whether the signature is correct (take out the signature part passed by the user and match the signature generated by the server)
            if (!string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1]))))))
            {
                return TokenType.Fail;
            }
            //Second, verify whether it is within the validity period (must be verified)
            var now = ToUnixEpochDate(DateTime.UtcNow);
            if (!(now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString())))
            {
                return TokenType.Expired;
            }

            //No need for custom authentication, no transfer or transfer null that will do
            if (validatePayLoad == null)
            {
                action(payLoad);
                return TokenType.Ok;
            }
            //And then carry out custom verification
            if (!validatePayLoad(payLoad))
            {
                return TokenType.Fail;
            }
            //May need to obtain jwt The data inside is easy to use
            action(payLoad);
            return TokenType.Ok;
        }

 

Where tokenttype is the return type, failure

public enum TokenType
    {
        Ok,
        Fail,
        Expired
    }

Two new verification methods in api LoginTest

/// <summary>
        /// Verification Token
        /// </summary>
        /// <param name="tokenStr">token</param>
        /// <returns></returns>
        [HttpGet]
        public ReturnModel ValiToken(string tokenStr)
        {
            var ret = new ReturnModel
            {
                TnToken = new TnToken()
            };
            bool isvilidate = tokenHelper.ValiToken(tokenStr);
            if(isvilidate)
            {
                ret.Code = 200;
                ret.Msg = "Token Verification successful";
                ret.TnToken.TokenStr = tokenStr;
            }
            else
            {
                ret.Code = 500;
                ret.Msg = "Token Validation failed";
                ret.TnToken.TokenStr = tokenStr;
            }
            return ret;
        }
        /// <summary>
        /// Verification Token With return status
        /// </summary>
        /// <param name="tokenStr"></param>
        /// <returns></returns>
        [HttpGet]
        public ReturnModel ValiTokenState(string tokenStr)
        {
            var ret = new ReturnModel
            {
                TnToken = new TnToken()
            };
            string loginID = "";
            TokenType tokenType = tokenHelper.ValiTokenState(tokenStr, a => a["iss"] == "WYY" && a["aud"] == "EveryTestOne", action => { loginID = action["loginID"]; });
            if (tokenType == TokenType.Fail)
            {
                ret.Code = 202;
                ret.Msg = "token Validation failed";
                return ret;
            }
            if (tokenType == TokenType.Expired)
            {
                ret.Code = 205;
                ret.Msg = "token Expired";
                return ret;
            }

            //..............Other logic
            var data = new List<Dictionary<string, string>>();
            var bb = new Dictionary<string, string>
            {
                { "Wyy", "123456" }
            };
            data.Add(bb);
            ret.Code = 200;
            ret.Msg = "Access successful!";
            ret.Data =data ;
            return ret;
        }

 

The above simple verification and support for custom verification are written. The next thing with status is to let us know clearly what status is when requesting login or data, whether the token is expired or not.

For the third parameter of ValiTokenState, I also have a system delegation. I think that the processing can verify the token, and I can also pick up a desired data by the way. Of course, in this way, the relevant logic can be mixed together to increase the code coupling. At that time, it can improve the efficiency without having to re analyze the data. Of course, the data can also be passed through the foreground, so how can I It depends on the actual situation. Here is just a package to provide such a method, which can also be used.

Its front-end request code

 $.ajax({
            type: "post",
            url: "https://localhost:44331/api/LoginTest/ValiToken?tokenStr="+ $("#tokenValue").val(),
            dataType: "json",
            async: true,
            data: { token: $("#tokenValue").val() },
            contentType: 'application/json',
            success: function (data) {
                console.log(data);             
            },
            error: function (data) {
                console.log("error" + data);
            }
        });

4. Implementation of universal token verification by filters in Api

Create a new folder Filter on the project, and a new Filter TokenFilter in the folder Filter

namespace JWTToken.Filter
{
    public class TokenFilter : Attribute, IActionFilter
    {
        private ITokenHelper tokenHelper;
        public TokenFilter(ITokenHelper _tokenHelper) //Get data access layer instance through dependency injection
        {
            tokenHelper = _tokenHelper;
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {

        }
        public void OnActionExecuting(ActionExecutingContext context)
        {
            ReturnModel ret = new ReturnModel();
            //Obtain token
            object tokenobj = context.ActionArguments["token"];

            if (tokenobj == null)
            {
                ret.Code = 201;
                ret.Msg = "token Cannot be empty";
                context.Result = new JsonResult(ret);
                return;
            }

            string token = tokenobj.ToString();

            string userId = "";
            //Verification jwt,Take it out at the same time jwt Users inside ID
            TokenType tokenType = tokenHelper.ValiTokenState(token, a => a["iss"] == "WYY" && a["aud"] == "EveryTestOne", action => { userId = action["userId"]; });
            if (tokenType == TokenType.Fail)
            {
                ret.Code = 202;
                ret.Msg = "token Validation failed";
                context.Result = new JsonResult(ret);
                return;
            }
            if (tokenType == TokenType.Expired)
            {
                ret.Code = 205;
                ret.Msg = "token Expired";
                context.Result = new JsonResult(ret);
            }
            if (!string.IsNullOrEmpty(userId))
            {
                //Pass parameters to controller(What parameters are needed can be made configurable. Add fields to the filter)
                //context.ActionArguments.Add("userId", Convert.ToInt32(userId));
            }
        }
    }
}

context.ActionArguments. This is the parameter token=xxx in the address bar when the previous request is made. This type of parameter is not the requested parameter, otherwise it will report an error;

Fill the filter in the startup as follows:

 services.AddScoped<TokenFilter>();

Where the token needs to be verified, add this filter directly

 

The front desk tries to request the GetList in the figure above

<input type="hidden" id="tokenValue" name="tokenValue" value="" />
<br /><br /><br />
<span>Token:</span><div id="txtval"></div><br />
<span>term of validity:</span><div id="txtvalTime"></div><br />

<div>
    <input type="button" value="Obtain Token" onclick="getToken()" /><br /><br /><br />
</div>
<input type="button" value="Obtain List" onclick="getList()" /><br />
<script src="~/Scripts/jquery-3.3.1.js"></script>
<script type="text/javascript">
    //Obtain token
    function getToken() {
        var data = JSON.stringify({ LoginID: "admin", Password: "admin888" });
        $.ajax({
            type: "post",
            url: "https://localhost:44331/api/LoginTest/Login",
            dataType: "json",
            async: true,
            data: data,
            contentType: 'application/json',
            success: function (data) {
                console.log(data);
                $("#txtval").html(data.tnToken.tokenStr);
                $("#txtvalTime").html(new Date(data.tnToken.expires).Format("yyyy-MM-dd hh:mm"));
                $("#tokenValue").val(data.tnToken.tokenStr);

            },
            error: function (data) {
                console.log("error" + data);
            }
        });
    }
    //Obtain list
    function getList() {
        var data = JSON.stringify();
        $.ajax({
            type: "post",
            url: "https://localhost:44331/api/Home/GetList?token="+ $("#tokenValue").val(),
            dataType: "json",
            async: true,
            data: { token: $("#tokenValue").val() },
            contentType: 'application/json',
            success: function (data) {
                console.log(data);
                $("#txtval").html(JSON.stringify(data));
                
             

            },
            error: function (data) {
                console.log("error" + data);
            }
        });
    }
    Date.prototype.Format = function (fmt) { //author: zhengsh 2016-9-5
        var o = {
            "M+": this.getMonth() + 1, //Month
            "d+": this.getDate(), //day
            "h+": this.getHours(), //hour
            "m+": this.getMinutes(), //branch
            "s+": this.getSeconds(), //second
            "q+": Math.floor((this.getMonth() + 3) / 3), //quarter
            "S": this.getMilliseconds() //Millisecond
        };
        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
            if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
    }
</script>

Now get token assignment in the hidden box and request

5. Using Swagger in Api

5.1 add Swagger related packages to the project

 

 

 

5.2configureeservices and Configure

#region Swagger
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Version = "v1",
                    Title = "Test interface documentation",
                    Description = "Test interface"
                });
                // by Swagger Set up xml Document comment path
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
                c.DocInclusionPredicate((docName, description) => true);
                //Add label to controller(describe)
                c.DocumentFilter<ApplyTagDescriptions>();//Show class name
                c.CustomSchemaIds(type => type.FullName);// Can solve the problem that the same class name will report an error
                //c.OperationFilter<AuthTokenHeaderParameter>();
            });
            #endregion
app.UseSwagger(c =>
            {
                c.RouteTemplate = "swagger/{documentName}/swagger.json";
            });
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Web App v1");
                c.RoutePrefix = "doc";//Set root access
                //c.DocExpansion(DocExpansion.None);//Fold
                c.DefaultModelsExpandDepth(-1);//Don't show Schemas
            });

5.3 modification of project attribute

5.4. Add interface class notes

 

See the effect

6. Summary

JWT's personal understanding is that the IssuerSigningKey of the API configuration file is encrypted as the secret key. After the client logs in, the request to obtain the token address bar is sent to the back-end. The request is decoded to obtain whether the IssuerSigningKey matches the one parsed by the back-end all the time. The backend can unload the boiler to receive the token to verify the access to API. The front-end can encapsulate a request to put the token in the parameter to avoid entering the token every time. The front-end can Session?

I wrote in a hurry after class. Welcome to add.

Topics: JSON encoding JQuery Javascript