developer tip

WebApi에서 OAuth Bearer 토큰 생성 및 Owin을 사용하여 클라이언트에 더 많은 정보를 반환합니다.

copycodes 2020. 11. 30. 17:57
반응형

WebApi에서 OAuth Bearer 토큰 생성 및 Owin을 사용하여 클라이언트에 더 많은 정보를 반환합니다.


WebApi와 Cordova 애플리케이션을 만들었습니다. Cordova 애플리케이션과 WebAPI간에 통신하기 위해 HTTP 요청을 사용하고 있습니다. WebAPI에서는 OAuth Bearer 토큰 생성을 구현했습니다.

public void ConfigureOAuth(IAppBuilder app)
    {
        var oAuthServerOptions = new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new SimpleAuthorizationServerProvider(new UserService(new Repository<User>(new RabbitApiObjectContext()), new EncryptionService()))
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(oAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

    }

그리고 이것은 SimpleAuthorizationServerProvider구현 내부에 있습니다.

 public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
       context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        // A little hack. context.UserName contains the email
        var user = await _userService.GetUserByEmailAndPassword(context.UserName, context.Password);

        if (user == null)
        {
            context.SetError("invalid_grant", "Wrong email or password.");
            return;
        }

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim("sub", context.UserName));
        identity.AddClaim(new Claim("role", "user"));

        context.Validated(identity);
    }

Cordova 앱에서 API에 대한 성공적인 로그인 요청 후 다음 JSON을 수신합니다.

{"access_token":"some token","token_type":"bearer","expires_in":86399}

문제는 사용자에 대한 추가 정보가 필요하다는 것입니다. 예를 들어, 데이터베이스에 UserGuid 필드가 있고 로그인에 성공하면 Cordova 앱으로 보내고 나중에 다른 요청에서 사용하려고합니다. 내가 아닌 다른 클라이언트에 반환하는 기타 정보를 포함 할 수 있습니다 "access_token", "token_type""expires_in"? 그렇지 않은 경우 어떻게 API를 기반으로 사용자를 가져올 수 access_token있습니까?


편집하다:

해결 방법을 찾은 것 같습니다. 내부에 다음 코드를 추가했습니다.GrantResourceOwnerCredentials

identity.AddClaim(new Claim(ClaimTypes.Name, user.UserGuid.ToString()));

그 후 다음과 같이 컨트롤러 내부의 GUID에 액세스합니다. User.Identity.Name

사용자 지정 이름으로 GUID를 추가 할 수도 있습니다. identity.AddClaim(new Claim("guid", user.UserGuid.ToString()));

전달자 토큰 JSON을 사용하여 클라이언트에 더 많은 데이터를 반환하는 방법이 있는지 여전히 알고 싶습니다.


원하는만큼 클레임을 추가 할 수 있습니다.
표준 클레임 집합을 추가 System.Security.Claims하거나 직접 만들 수 있습니다.
클레임은 토큰에서 암호화되므로 리소스 서버에서만 액세스 할 수 있습니다.

클라이언트가 토큰의 확장 속성을 읽을 수 있도록하려면 다른 옵션이 AuthenticationProperties있습니다..

클라이언트가 액세스 할 수 있도록 무언가를 추가하고 싶다고 가정 해 보겠습니다. 그게 방법입니다.

var props = new AuthenticationProperties(new Dictionary<string, string>
{
    { 
        "surname", "Smith"
    },
    { 
        "age", "20"
    },
    { 
    "gender", "Male"
    }
});

이제 위에 추가 한 속성으로 티켓을 만들 수 있습니다.

var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);

That's the result your client will fetch:

.expires: "Tue, 14 Oct 2014 20:42:52 GMT"
.issued: "Tue, 14 Oct 2014 20:12:52 GMT"
access_token: "blahblahblah"
expires_in: 1799
age: "20"
gender: "Male"
surname: "Smith"
token_type: "bearer"

On the other hand if you add claims you will be able to read them in your resource server in your API controller:

public IHttpActionResult Get()
{
    ClaimsPrincipal principal = Request.GetRequestContext().Principal as ClaimsPrincipal;

    return Ok();
}

Your ClaimsPrincipal will contain your new claim's guid which you've added here:

identity.AddClaim(new Claim("guid", user.UserGuid.ToString()));

If you want to know more about owin, bearer tokens and web api there's a really good tutorial here and this article will help you to grasp all the concepts behind Authorization Server and Resource Server.

UPDATE:

You can find a working example here. This is a Web Api + Owin self-hosted.
There's no database involved here. The client is a console application (there's a html + JavaScript sample as well) which call a Web Api passing credentials.

As Taiseer suggested, you need to override TokenEndpoint:

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);
}

Enable 'Multiple Startup Projects' from Solution -> Properties and you can run it straight away.


My recommendation is not to add extra claims to the token if not needed, because will increase the size of the token and you will keep sending it with each request. As LeftyX advised add them as properties but make sure you override TokenEndPoint method to get those properties as a response when you obtain the token successfully, without this end point the properties will not return in the response.

 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);
    }

You can check my repo here for complete example. Hope it will help.

참고URL : https://stackoverflow.com/questions/26357054/return-more-info-to-the-client-using-oauth-bearer-tokens-generation-and-owin-in

반응형