-
-
Notifications
You must be signed in to change notification settings - Fork 194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Supports authentication #42
Comments
Hey @5yunus2efendi I have worked on your authentication issue. Actually it was in my backlog... for a long time. I have made a bunch of tests, and my solution is based on a I will go deeper in the explanation, but to let you know, here is the most important code, when you implement your proxy on the client side: var proxyClientProvider = new WebProxyClientProvider(new Uri("http://localhost:58507/api/authsync"));
// adding bearer auth
if (authenticationResult != null && authenticationResult.AccessToken != null)
proxyClientProvider.AddCustomHeader("Authorization", authenticationResult.CreateAuthorizationHeader());
var agent = new SyncAgent(clientProvider, proxyClientProvider);
var r = await agent.SynchronizeAsync(); Ok, now here is the full story IntroductionTo be able to authenticate your sync queries, the first assumption is to work with a client -server project, based on the For more information about how to implement a webserver project, see the documentation here : Implementing a web server proxy Since your server is a web server, you have to be sure no one is able to reach your sync endpoint, with no autorization... Server SideOn the server side, it's not mandatory to implement a full OAUTH2 (or whatever you want) server. For this sample, I will work with the Azure AD V2 endpoints, that you can configure here: http://apps.dev.microsoft.com/ My application is configured as a Web Api endpoint, with a custom scope, called access_as_user
Once you're ready, you can modify your ASP.NET Core 2.0 web server, to become a JwtBearer authenticated web sever. First of all, in the var connectionString = Configuration.GetSection("ConnectionStrings")["DefaultConnection"];
services.AddSyncServer<SqlSyncProvider>(connectionString, configuration =>
{
var s = new string[] { "Employees" };
configuration.Add(s);
configuration.DownloadBatchSizeInKB = 1000;
});
// Use bearer schema for authentication
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
var azureAdOptions = Configuration.GetSection("AzureAdV2").Get<AzureAdOptions>();
options.Audience = azureAdOptions.ClientId;
options.Authority = azureAdOptions.Authority;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = false
};
});
services.AddMvc(); As you can see, the {
"AzureAdV2": {
"Authority": "https://login.microsoftonline.com/common/v2.0",
"ClientId": "99362e01-d41a-4370-95ce-db9e1d51796f"
}
} Ok, now we just have to mark any controller with the [Authorize]
[Route("api/[controller]")]
public class AuthSyncController : Controller
{
// proxy to handle requests and send them to SqlSyncProvider
private WebProxyServerProvider webProxyServer;
// Injected thanks to Dependency Injection
public AuthSyncController(WebProxyServerProvider proxy)
{
webProxyServer = proxy;
}
// POST api/values
[HttpPost]
public async Task Post()
{
// Checking the scope is optional
// The [Authorize] class attribute is enough, since it prevents anyone to access
// this controller without a Bearer token
// Anyway you can have a more detailed control using the claims !
string scope = (User.FindFirst("http://schemas.microsoft.com/identity/claims/scope"))?.Value;
string user = (User.FindFirst(ClaimTypes.NameIdentifier))?.Value;
if (scope != "access_as_user")
{
this.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
await webProxyServer.HandleRequestAsync(this.HttpContext);
}
} As you can see, you can fine tuning your autorization process with the claims. Client SideOn the client side, you will have to authenticate your user, to be able to retrieve a bearer token, and then use it to authenticate your sync process. // Authentication sample config
// -------------------------------------------------------------------
// App is registered in https://apps.dev.microsoft.com
// -------------------------------------------------------------------
string ClientId = "99362e01-d41a-4370-95ce-db9e1d51796f"; // AAD V2
PublicClientApplication publicClientApp = new PublicClientApplication(ClientId);
string[] scopes = new string[] { "api://99362e01-d41a-4370-95ce-db9e1d51796f/access_as_user" };
AuthenticationResult authenticationResult = null;
try
{
var user = publicClientApp.Users.FirstOrDefault();
authenticationResult = await publicClientApp.AcquireTokenSilentAsync(scopes, user);
}
catch (MsalUiRequiredException)
{
try
{
authenticationResult = await publicClientApp.AcquireTokenAsync(scopes);
}
catch (MsalException msalex)
{
Debug($"Error Acquiring Token");
}
}
catch (Exception ex)
{
Debug(ex.Message);
} Then I use the bearer token to authenticate my sync request: var clientProvider = new SqliteSyncProvider("employees.db");
var proxyClientProvider = new WebProxyClientProvider(
new Uri("http://localhost:58507/api/authsync"));
// adding bearer auth
if (authenticationResult != null && authenticationResult.AccessToken != null)
proxyClientProvider.AddCustomHeader("Authorization", authenticationResult.CreateAuthorizationHeader());
var agent = new SyncAgent(clientProvider, proxyClientProvider);
agent.SyncProgress += (s, a) => Debug(a.Message + a.PropertiesMessage);
try
{
var r = await agent.SynchronizeAsync();
Debug("TotalChangesDownloaded: " + r.TotalChangesDownloaded);
}
catch (Exception ex)
{
Debug("Error during sync " + ex.Message);
} Conclusion and sampleThe authentication is fully integrated with any kind of authentication you want to use. In my next commit, you will find a full sample in the /Samples folder (I hope before the end of the week) Let me know if it's ok for you ? Sebastien |
sounds great, I already implemented |
Just for information, what kind of technic did you use to implement the server side ? My sample is based on BTW, the version 0.1.9 is actually implementing the needed properties and methods to works properly with authentication. Check the new version here : https://www.nuget.org/packages/Dotmim.Sync.Web/0.1.9 For instance, once nuget cache website will be updated, 0.1.9 will be the default version. |
for server-side I am using It's looking good, I use the authentication and it's working! |
Oh nice; |
Here is the sample: AFAIK, |
Would be great if supports authentication, especially when dealing with Web API
The text was updated successfully, but these errors were encountered: