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;
# endregion
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
);
//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"
);