REST API samples SF v5
Hi
Does anyone have any examples of using the REST API against SF v5?
I found the sample client app and have used to be able to login using Claims Auth and can happily list users/roles in my system.
I now need to be able to create new roles and users.
The SVC help file suggests that I need to do PUT to localhost:50049/.../ which seem reasonable except if I'm creating a new role I don't have a roleId to specify. I tried leaving that out and just using Roles.svc or Roles.svc/?provider=default but anything I've tried always come back with the bad request error suggesting that the URI is incorrect.
On a related note, does anyone know how to signin and have it force signout if it finds that the username is already logged in (e.g. from a browser session)?
Thanks
Chris,
Something like Fiddler is going to take you a long way when using the APIs. Fire it up, do whatever it is that you're trying to accomplish in the backend and then watch the calls being made. Sometimes you can just copy the call from Fiddler and paste it right back into your browser or wherever you want it! :)
Hi Chris,
Did you ever figure out how to force a logout of any existing session for a particular user? I'm in need of the same functionality, and can't figure it out either. If you've found a solution, I would appreciate it if you could forward it along to me.
FYI, I've tried using Charles (my equivalent to Fiddler) to figure out how the web site does it, but there's a lot of extra stuff going on in the HTTP headers that I don't understand, and if I ignore that stuff, I don't see that there's enough info in the HTTP calls to cause a logout. I've tried lots of things, but nothing has worked.
S
Sorry - I don't finish up this piece of work in the end. I didn't solve that problem and opted for a different solution using custom membership providers instead.
Hello. Has anyone got a resolution for this problem? I am using the IUsers::CreateUser method (~/Sitefinity/Services/Security/Users.svc//create/userId/?provider=provider) but can't get it to work without a 405 Method Not Allowed response. If someone can please post a working sample of a call to CreateUser via the REST API, including authentication, it would be much appreciated.
Here's my HTTP request (I'm already authenticated in this example using the token returned from ~/Sitefinity/Authenticate):
PUT myhost/.../ HTTP/1.1
User-Agent: Fiddler
Host: myhost
Authorization: WRAP access_token="mytoken"
Content-Length: 94
Content-type: application/json
"Email":"mynewuseremail@mail.com","Password":"mynewuserpassword","UserName":"mynewusername"
Hello Scott,
We have replied back i9n the support thread you had open on the same issue, you can check our response there. For your convenience I'm copying our response here as well:
"
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.Serialization;namespace SFWinformsClient.Model.User [DataContract] public class RolesOfUser [DataMember] public string ProviderName get; set; [DataMember] public string RoleId get; set; [DataMember] public string RoleName get; set; [DataContract] public class User [DataMember] public bool AvatarImageSmallerWidth get; set; [DataMember] public string AvatarImageUrl get; set; [DataMember] public string AvatarThumbnailUrl get; set; [DataMember] public string Comment get; set; [DataMember] public DateTime CreationDate get; set; [DataMember] public string DisplayName get; set; [DataMember] public string Email get; set; [DataMember] public bool IsApproved get; set; [DataMember] public bool IsBackendUser get; set; [DataMember] public bool IsLockedOut get; set; [DataMember] public bool IsLoggedIn get; set; [DataMember] public object LastActivityDate get; set; [DataMember] public object LastLockoutDate get; set; [DataMember] public object LastLoginDate get; set; [DataMember] public DateTime LastPasswordChangedDate get; set; [DataMember] public object Password get; set; [DataMember] public object PasswordAnswer get; set; [DataMember] public string PasswordQuestion get; set; [DataMember] public object ProfileData get; set; [DataMember] public string ProviderName get; set; [DataMember] public string ProviderUserKey get; set; [DataMember] public string RoleNamesOfUser get; set; [DataMember] public List<RolesOfUser> RolesOfUser get; set; [DataMember] public string UserID get; set; [DataMember] public string UserName get; set; # region Create user private void button2_Click(object sender, EventArgs e) CreateUser(); public void CreateUser() string responseBody; var userId = Guid.NewGuid().ToString(); var userProviderName = "Default"; //remove the + DateTime.UtcNow.Second.ToString(); it's used for easier testing only!!! var firstName = "John " + DateTime.UtcNow.Second.ToString(); var lastName = "Smith " + DateTime.UtcNow.Second.ToString(); var userName = "jsmith " + DateTime.UtcNow.Second.ToString(); var password = "password"; var mail = "jsmith" + DateTime.UtcNow.Second.ToString() + "@wcf.com"; var secretQuestion = ""; var secretAnswer = ""; var roleName = "BackendUsers"; var roleProviderName = "AppRoles"; //get this from SecurityConfig.config var backendUsersRoleId = "170fc761-eb01-4d2f-9706-58634fb5de06"; var rolesForUser = new List<SFWinformsClient.Model.User.RolesOfUser>(); rolesForUser.Add(new SFWinformsClient.Model.User.RolesOfUser() RoleName = roleName, RoleId = backendUsersRoleId, ProviderName = roleProviderName ); var defaultAvataImageUrl = "/SFRes/images/Telerik.Sitefinity.Resources/Images.DefaultPhoto.png"; //set WcfUser data members SFWinformsClient.Model.User.User user = new SFWinformsClient.Model.User.User(); user.AvatarImageSmallerWidth = false; user.AvatarImageUrl = defaultAvataImageUrl; user.AvatarThumbnailUrl = defaultAvataImageUrl; user.Comment = ""; user.CreationDate = DateTime.UtcNow; user.DisplayName = firstName + " " + lastName; user.Email = mail; user.IsApproved = true; user.IsBackendUser = true; user.IsLockedOut = false; user.IsLoggedIn = false; user.LastActivityDate = null; user.LastPasswordChangedDate = DateTime.UtcNow; user.Password = password; user.PasswordAnswer = secretAnswer; user.PasswordQuestion = secretQuestion; user.ProviderName = userProviderName; user.RoleNamesOfUser = roleName; user.RolesOfUser = rolesForUser; user.UserID = userId; user.UserName = userName; //Pass the default user profile type, it will be resolved automatically //Please note currently there is no implementation to create a profile and set the properties by defualt //they need to be set additionally from the backend users adminsitration user.ProfileData = "\"Telerik.Sitefinity.Security.Model.SitefinityProfile\": "; JsonSerializerSettings settings = new JsonSerializerSettings(); settings.DateParseHandling = DateParseHandling.DateTime; settings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat; string jsonString = JsonConvert.SerializeObject(user, settings); //string replacedString = Regex.Replace(jsonString, "\"", "\\\""); //replacedString = String.Format("\"0\"", replacedString); byte[] data = Encoding.UTF8.GetBytes(jsonString); helper.CallService( ServiceHelper.UsersUrl + "/create/00000000-0000-0000-0000-000000000000/?provider=" + userProviderName, data, "PUT", out responseBody, "application/json" ); textBox1.Text = jsonString; var a = responseBody; textBox2.Text = a; # endregionvar roleName = "BackendUsers"; var roleProviderName = "AppRoles"; //get this from SecurityConfig.config var backendUsersRoleId = "170fc761-eb01-4d2f-9706-58634fb5de06"; var rolesForUser = new List<SFWinformsClient.Model.User.RolesOfUser>(); rolesForUser.Add(new SFWinformsClient.Model.User.RolesOfUser() RoleName = roleName, RoleId = backendUsersRoleId, ProviderName = roleProviderName );//Pass the default user profile type, it will be resolved automatically //Please note currently there is no implementation to create a profile and set the properties by defualt //they need to be set additionally from the backend users adminsitration user.ProfileData = "\"Telerik.Sitefinity.Security.Model.SitefinityProfile\": ";Here's what I did. Seems to work well.
First create a controller to call into the Sitefinity SecurityManager methods..
public class UsersController : ApiController [HttpPost] public UserLoggingReason AuthenticateUser([FromBody] Credentials credentials) return SecurityManager.AuthenticateUser(credentials); [HttpGet] public void Logout() SecurityManager.Logout(); [HttpPost] public void ForceLogout([FromBody] Credentials credentials) SecurityManager.Logout(credentials); Then here's the client I wrote to do the logging in / out / and force logout when required.
/// <summary> /// Assists accessing secure Sitefinity resources via an HTTP client by running a task wrapped with a log in and log out. /// Requires a server side implementation of Authenticate(credentials), Logout(void) and ForceLogout(credentials) /// </summary> public class SitefinityClient : IDisposable private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly SitefinityClientOptions _options; private readonly HttpClientHandler _handler; private readonly HttpClient _client; private readonly object _credentials; public SitefinityClient(SitefinityClientOptions options) _options = options; _credentials = new MembershipProvider = "", Persistent = true, UserName = _options.UserName, Password = _options.Password ; _handler = new HttpClientHandler() CookieContainer = new CookieContainer() ; _client = new HttpClient(_handler) BaseAddress = new Uri(_options.BaseUrl) ; /// <summary> /// Runs the async task (or lambda) with login and logout. /// </summary> /// <param name="asyncTask">The asynchronous task (or lambda).</param> /// <returns></returns> /// <exception cref="System.Exception"></exception> public async Task RunWithLoginLogout(Func<HttpClient, Task> asyncTask) Logger.Info(string.Format("Logging in as 0", _options.UserName)); var logInResult = await Login(); if (logInResult == UserLoggingReason.UserAlreadyLoggedIn || logInResult == UserLoggingReason.UserLoggedFromDifferentComputer || logInResult == UserLoggingReason.UserLoggedFromDifferentIp) Logger.Warn("User already logged in (0). Forcing log out..", logInResult); await ForceLogout(); Logger.Info(string.Format("Logging in as 0", _options.UserName)); logInResult = await Login(); if (logInResult != UserLoggingReason.Success) throw new Exception(string.Format("Log in failed: 0", logInResult)); ExceptionDispatchInfo taskEx = null; try await asyncTask(_client); catch (Exception ex) taskEx = ExceptionDispatchInfo.Capture(ex); await Logout(); if (taskEx != null) taskEx.Throw(); protected async Task<UserLoggingReason> Login() var resp = await _client.PostAsJsonAsync(_options.LoginUrl, _credentials); resp.EnsureSuccessStatusCode(); return await resp.Content.ReadAsAsync<UserLoggingReason>(); protected async Task ForceLogout() var resp = await _client.PostAsJsonAsync(_options.ForceLogoutUrl, _credentials); resp.EnsureSuccessStatusCode(); protected async Task Logout() Logger.Info("Logging out"); try await _client.GetAsync(_options.LogoutUrl); catch (Exception ex) Logger.Error("Log out failed", ex); #region IDisposable public void Dispose() Dispose(true); GC.SuppressFinalize(this); protected virtual void Dispose(bool disposing) if (disposing) if (_client != null) _client.Dispose(); if (_handler != null) _handler.Dispose(); #endregion Then assuming you had a web api method you wanted to post some data to which requires authentication you'd use it (btw in the controller method you can force authentication using the appropriate overload of ServiceUtility.RequestAuthentication)..
using (var sfClient = new SitefinityClient(options)) var uploadTask = sfClient.RunWithLoginLogout(async (httpClient) => Logger.Info("Uploading..."); await httpClient.PostAsJsonAsync(options.UploadUrl, data); ); uploadTask.Wait();Logger.Info("Finished OK");