本文介绍了webapi中基于令牌的实现可保护端点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有Web服务的Web应用程序,客户端将使用我的Web应用程序注册其应用程序.

I am having a web application with web service and client will register their application using my web application.

现在,客户端将具有类型为 SPA或移动应用的应用,并且他们将从其应用中使用我的网络服务.

Now client will have application of type SPA or mobile apps and they will consume my webservices from their apps.

因此,我将实现基于令牌的机制来保护对端点的访问.

So I would be implementing token based mechanism for securing access to my endpoints.

1)但是在这里,我感到困惑的是,我应该使用任何框架来生成访问令牌,还是可以使用任何库来生成我将作为响应发送的任何随机字符串,例如:

1) But here I am confused that shall I use any framework to generate access token or I can use any library which will generate any random string which i will send in response.for instance something like this :

TokenId = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("+", "_")

因此,在注册应用程序时,如果客户端已为其应用程序启用身份验证,则将对用户进行验证,然后我将返回访问令牌,并将具有该用户ID的访问令牌保存在我的数据库中.

So while registering application if client have enabled authentication for their application then user will be validated and then I will return access token and also save accesstoken in my database with that user id.

所以我的数据库表如下所示,用于存储经过验证的访问令牌:

So my database table would be like below for storing validated accesstoken :

Id(autogenerated)   accesstoken    userid   clientid    createdat    expiresat

因此,在对用户进行身份验证之后,现在如果用户要访问任何受保护的资源,则用户需要在后续的标头调用中传递此访问令牌.

So after user is authenticated and now if user want to access any protected resources then user need to pass this access token in subsequent call in header.

所以我该怎么做,我将从标头中获取访问令牌,然后针对该数据库验证该访问令牌,然后允许对我受保护的资源的访问,否则,明智的用户将获得授权.

So what I will do I will get access token from header and then validate that accesstoken against that database and then allow access to my protected resource other wise user would get authorized.

我已经看到很多与此相关的东西,所以基本上是oauth2,我想实现它.

I have seen lots of things related to this so basically this is oauth2 and I want to implement this.

我已经看到 Openid connect (该项目没有甚至编译),它位于oauth2之上,用于身份验证,而oauth2将用于授权.

I have seen Openid connect(this project doesnt even compile) which is on top of oauth2 and which is used for authentication and oauth2 will be used for authorization.

但是在这里,因为我将访问令牌存储在数据库中,所以我对此有疑问:

But here as I am storing access token in my database so here is my doubt related to that :

2)现在我是否需要openconnectid(但该项目甚至没有编译)来验证访问令牌,或者因为我将访问令牌存储在数据库中,所以我不需要openconnectid?

2) Now do I need openconnectid (but this project doesn't even compile) for validating access token or as I am having storing access token in my database I don't need openconnectid?

3)我想实现asp.net身份,但是随后我将收到动态数据库连接字符串,并且正如我所见,asp.net身份主要与实体框架一起使用,我找不到可以使用ado.net的任何源.使用SQL查询验证用户名和密码.我知道我可以做这样的事情:

3) I want to implement asp.net identity but then I will receive dynamic database connection string and as i have seen asp.net identity mostly works with entity framework I couldn't find any source where I could use ado.net to validate username and password using SQL query. I know I can do something like this :

按照此处所述,制作实现IUser的自定义用户类定义一个实现

public class UserStoreService 
     : IUserStore<CustomUser>, IUserPasswordStore<CustomUser>

但是我将没有此信息,因为我没有固定的连接字符串.连接字符串再次通过客户端注册存储在数据库中.

But I won't be having this information as I don't have fixed connection string.connection string again is stored in database with client registration.

4)我们为用户提供了一个固定的端点,客户端可以通过该端点创建管理员,因此我将使用RSA算法对密码进行哈希处理,然后将其存储在数据库中.因此,现在我需要使用asp.net身份吗?

4) We have given user a fixed endpoint through which client can create an admin so for that I will use my RSA algorithm for password hashing and then store it in database. So with this now do i need to use asp.net identity?

5)我已经看到很多以下基于令牌的实现的链接,但是我没有得到它们在哪个部分验证accesstoken的信息,但是由于我将accesstoken存储在数据库中,因此我需要使用以下任何实现?

5) I have seen lots of following link with token based implementation but I am not getting where they are validating accesstoken in which part but now as I am having accesstoken stored in my database do I need to use any of the following implementation?

http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/

http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/

6)而且,如果对于任何客户端,如果客户端不希望对其各自的应用程序进行身份验证,那么我要做的是,我将没有该用户名密码验证,但是我只会生成accesstoken,然后发送响应,因此在随后的每个请求中,都将访问令牌传递给访问受保护的资源.您认为这有意义吗?

6) Moreover if for any client if client don't want authentication for its respective application then what I will do is I will don't have that username password validation but I will simply generate accesstoken and then send in response so then in every subsequent request that access token will be pass to access protected resources.Do you think this make sense?

我从未见过任何将访问令牌存储在数据库中的示例,而将访问令牌存储在数据库中的问题将是我每次必须调用数据库以验证每个端点的访问令牌.

I have never seen any example where access token is store in database and problem with storing access token in database would be I have to make a call to database every time to validate access token for each endpoint.

更新:

我的Web服务引擎的用例为:

Use case of my webservice engine would be:

1)支持多个客户端应用程序.

1) Support multiple client application.

2)以令牌管理的形式管理每个客户端应用程序的用户会话.所以在这里,由于本文的大部分内容都以身份存储访问令牌,并且该身份在[Authorize]属性中进行了验证,在该属性中,访问令牌也得到了验证,并允许该用户基于该用户访问受保护的资源.这是我到目前为止的理解.

2) Manage user session in the form of token management for each client application. So here as most of the article is storing accesstoken in identity and that identity is validated inside [Authorize] attribute in which accesstoken is also validated and based on that user is allowed to access protected resources.This is what my understanding is up until now.

那么,如果我还要用户身份并将用户上下文存储在支持多个客户端应用程序的身份中,是一个好主意吗?

So if I also user identity and store user context inside identity supporting multiple client application is a good idea?

推荐答案

否,您不需要将access_token存储在数据库中.您可以解密JWT并读取信息,因为您是使用密钥对它进行加密的人. (默认情况下,这是机器密钥.)

No, you don't need to store the access_token on the database. You can decrypt the JWT and read the information as you are the one who encrypts it with a secret key. (By default it's the machine key.)

身份无法使用Oauth进行自我支持.您只需要正确配置它.您可以在Startup.Auth.cs中设置 OAuthAuthorizationServerOptions 的配置.示例代码如下.我已尝试在代码的注释中回答您的大多数问题.

Identity has a off the self support for Oauth. You have to just configure it properly. You can set-up the configuration for OAuthAuthorizationServerOptions in the Startup.Auth.cs. Sample code as follows. I have tried to answer most of your question in comments in the code.

public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    public void ConfigureOAuth(IAppBuilder app)
    {
        // Configure the application for OAuth based flow
        PublicClientId = "theDragonIsAlive";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new YourOwnApplicationOAuthProvider(PublicClientId),
            //AuthorizeEndpointPath = new PathString("/Access/Account"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(7)
            //AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

    }

public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
    private readonly string _publicClientId;

    public ApplicationOAuthProvider(string publicClientId)
    {
        if (publicClientId == null)
        {
            throw new ArgumentNullException("publicClientId");
        }

        _publicClientId = publicClientId;
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
        // This where you are validating the username and password credentials.
        ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

        if (user == null)
        {
            context.SetError("Dragon Fire:", "The user name or password is incorrect. You shall be burnt.");
            return;
        }

        ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
           OAuthDefaults.AuthenticationType);

        AuthenticationProperties properties = CreateProperties(user.UserName);
        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
        context.Validated(ticket);
        context.Request.Context.Authentication.SignIn(oAuthIdentity);
    }

    public override Task TokenEndpoint(OAuthTokenEndpointContext context)
    {
        foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
        {
            context.AdditionalResponseParameters.Add(property.Key, property.Value);
        }

        return Task.FromResult<object>(null);
    }

    // This method is where you will create the client access token.
    // First you get the client, you can place values from the client record into the tokens claim collection.
    // You then create a new ClaimsIdentity.
    // You add some claims, in the example client name is added.
    // Create an AuthenticationTicket using your claims identity.
    // Validate the ticket (you do need to do this or the client will be considered unauthenticated)
    //public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
    //{
    //    var client = clientService.GetClient(context.ClientId);
    //    var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
    //    oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, client.ClientName));
    //    var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
    //    context.Validated(ticket);
    //    return base.GrantClientCredentials(context);
    //}

    // This method has to be implmented when you are maintaining a list of clients which you will allow.
    // This method is for validating the input, you can used this method to verify the client id and secret are valid.
    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        //string clientId;
        //string clientSecret;
        //context.TryGetFormCredentials(out clientId, out clientSecret);

        //if (clientId == "1234" && clientSecret == "12345")
        //{
        //    context.Validated(clientId);
        //}

        //return base.ValidateClientAuthentication(context);

        // Resource owner password credentials does not provide a client ID.
        if (context.ClientId == null)
        {
            context.Validated();
        }

        return Task.FromResult<object>(null);
    }

    public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
    {
        if (context.ClientId == _publicClientId)
        {
            Uri expectedRootUri = new Uri(context.Request.Uri, "/");

            if (expectedRootUri.AbsoluteUri == context.RedirectUri)
            {
                context.Validated();
            }
        }

        return Task.FromResult<object>(null);
    }

    public static AuthenticationProperties CreateProperties(string userName)
    {
        IDictionary<string, string> data = new Dictionary<string, string>
        {
            { "userName", userName }
        };
        return new AuthenticationProperties(data);
    }
}

上面的示例代码没有单独的客户端分类.它将所有用户视为单一类型的客户端.但是我在注释中给出了一些示例代码,这些代码将指导您开始正确的方向.

The sample code above does not have separate client classifications. It will treat all users as a single type of client. But I have given some example code in the comments which will guide you to get started in the right direction.

免责声明:我还不是专家,我的设置也有所不同.我在Owin上有一个现有的MVC应用程序,必须在其之上构建一个webapi.这是我的原型代码,它完成了工作.您将不得不为您的生产代码进行改进.玩得开心,祝你好运.

Disclaimer: I am not an expert on this(yet) and my setup is different. I had an existing MVC application with Owin and I had to build a webapi on top of it. This was my prototype code and it did the job. You will have to improve in it for your production code. Have fun and good luck.

这篇关于webapi中基于令牌的实现可保护端点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-30 15:32