I am building an API for login and registration using loopback framework.
Loopback provides, by default, model User for login, register and other similar stuff. Default way to provide user's credentials in LoopBack is username-password/email-password but I want to use mobileNo-password/email-password as user's login credentials. So how can I do that? How can I change default credential option in User model?
You can achieve that in two ways:
If not using username field in User model, you can use it to store mobile number, mobileNo.
You have to edit user.js to accept mobileNo field as login credentials. User.login and User.normalizeCredentials are used for login process, so you can edit them like provided in the code snippet.
Note: Don't forget to add mobileNo to user.json
User.normalizeCredentials method
`User.normalizeCredentials = function(credentials, realmRequired, realmDelimiter) {
var query = {};
credentials = credentials || {};
if (!realmRequired) {
if (credentials.email) {
query.email = credentials.email;
} else if (credentials.mobileNo) {
query.mobileNo = credentials.mobileNo;
}
} else {
if (credentials.realm) {
query.realm = credentials.realm;
}
var parts;
if (credentials.email) {
parts = splitPrincipal(credentials.email, realmDelimiter);
query.email = parts[1];
if (parts[0]) {
query.realm = parts[0];
}
} else if (credentials.mobileNo) { //added mobileNo.
parts = splitPrincipal(credentials.mobileNo, realmDelimiter);
query.mobileNo = parts[1];
if (parts[0]) {
query.realm = parts[0];
}
}
}
return query;
};`
User.login method
`User.login = function(credentials, include, fn) {
.
.
.
.
.
if (!query.email && !query.mobileNo) {
var err2 = new Error('Mobile number or email is required');
err2.statusCode = 400;
err2.code = 'MOBILE_NUMBER_EMAIL_REQUIRED';
fn(err2);
return fn.promise;
}
}`
Related
This is my controller code and I need to mock GetTokenDetails() method to conduct XUnit test on DecodeToken function. Am I doing in right way or not?
[HttpGet]
[Authorize(Roles = "Admin")]
[Route("DecodeToken")]
public IActionResult DecodeToken()
{
if (ModelState.IsValid)
{
var tokenResult = GetTokenDetails();
var result = _employeeService.ServiceDecodeToken(tokenResult.UserName, tokenResult.Role);
if (result.Httpcode == 200)
{
return Ok(result);
}
else
{
return StatusCode(500, result);
}
}
else
return BadRequest();
}
public GetTokenDetailsDto GetTokenDetails()
{
var token = HttpContext.Request.Headers["Authorization"].ToString();
var tokenbearer = token.Split(' ');
var handler = new JwtSecurityTokenHandler();
var decodedtoken = handler.ReadJwtToken(tokenbearer[1]);
string user = decodedtoken.Claims.Where(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name").FirstOrDefault().ToString();
string role = decodedtoken.Claims.Where(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role").FirstOrDefault().ToString();
var usr = user.Split(":");
var rol = role.Split(":");
string userName = usr[2].Trim();
string userRole = rol[2].Trim();
GetTokenDetailsDto getTokenDetailsDto = new GetTokenDetailsDto()
{
UserName = userName,
Role = userRole,
};
return getTokenDetailsDto;
}
First, Generally, I don't think there is a right way to do something.
There are multiple right ways to do it :). You just need to pick one or create one.
Second, I suggest you to create a new Dotnet standard Project under the same Solution and separate the logic from controllers. This way, you can create a Unit test project and import only the logic project.
Third, I see some points in your code that you are reading some value from the context( which is not avaiable in testing environment). For example, HttpContext.Request.Headers["Authorization"]. these kind of data should be in the input arguments of the function GetTokenDetails, so you can provide some sample data to test in your UnitTestProject. Something like this:
public GetTokenDetailsDto GetTokenDetails(string token)
{
var tokenbearer = token.Split(' ');
var handler = new JwtSecurityTokenHandler();
var decodedtoken = handler.ReadJwtToken(tokenbearer[1]);
string user = decodedtoken.Claims.Where(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name").FirstOrDefault().ToString();
string role = decodedtoken.Claims.Where(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role").FirstOrDefault().ToString();
var usr = user.Split(":");
var rol = role.Split(":");
string userName = usr[2].Trim();
string userRole = rol[2].Trim();
GetTokenDetailsDto getTokenDetailsDto = new GetTokenDetailsDto()
{
UserName = userName,
Role = userRole,
};
return getTokenDetailsDto;
}
I need to get sitecore information that collected from anonymous users to give him availability to export it or opt out - [GDPR]
any idea about contact ID for anonymous !
The way of doing it is dependent on the sitecore version.
Sitcore 9 you can use right to be forgotten
Sitecore 8+ you have to implement the feature from scratch.
Regarding Anonymous user - If the user is really anonymous, then you done need to worry about the GDPR (my view). But sometimes we map user email and sensitive personal info to anonymous user by using forms or WFFM. You can use email address of that user to query xDB (Contact Identifiers) to get the contact and contactID. Then reset informations.
Also: please note that based on WFFFM save action config, anonymous user will store in Core DB and Contact List.
To forget a user, you can use the following code. It will execute the ExecuteRightToBeForgotten function on the contact and scrub their data.
Forget User
public bool ForgetUser()
{
var id = _contactIdentificationRepository.GetContactId();
if (id == null)
{
return false;
}
var contactReference = new IdentifiedContactReference(id.Source, id.Identifier);
using (var client = _contactIdentificationRepository.CreateContext())
{
var contact = client.Get(contactReference, new ContactExpandOptions());
if (contact != null)
{
client.ExecuteRightToBeForgotten(contact);
client.Submit();
}
}
return false;
}
Fake up some data
public void FakeUserInfo()
{
var contactReference = _contactIdentificationRepository.GetContactReference();
using (var client = SitecoreXConnectClientConfiguration.GetClient())
{
// we can have 1 to many facets
// PersonalInformation.DefaultFacetKey
// EmailAddressList.DefaultFacetKey
// Avatar.DefaultFacetKey
// PhoneNumberList.DefaultFacetKey
// AddressList.DefaultFacetKey
// plus custom ones
var facets = new List<string> { PersonalInformation.DefaultFacetKey };
// get the contact
var contact = client.Get(contactReference, new ContactExpandOptions(facets.ToArray()));
// pull the facet from the contact (if it exists)
var facet = contact.GetFacet<PersonalInformation>(PersonalInformation.DefaultFacetKey);
// if it exists, change it, else make a new one
if (facet != null)
{
facet.FirstName = $"Myrtle-{DateTime.Now.Date.ToString(CultureInfo.InvariantCulture)}";
facet.LastName = $"McSitecore-{DateTime.Now.Date.ToString(CultureInfo.InvariantCulture)}";
// set the facet on the client connection
client.SetFacet(contact, PersonalInformation.DefaultFacetKey, facet);
}
else
{
// make a new one
var personalInfoFacet = new PersonalInformation()
{
FirstName = "Myrtle",
LastName = "McSitecore"
};
// set the facet on the client connection
client.SetFacet(contact, PersonalInformation.DefaultFacetKey, personalInfoFacet);
}
if (contact != null)
{
// submit the changes to xConnect
client.Submit();
// reset the contact
_contactIdentificationRepository.Manager.RemoveFromSession(Analytics.Tracker.Current.Contact.ContactId);
Analytics.Tracker.Current.Session.Contact = _contactIdentificationRepository.Manager.LoadContact(Analytics.Tracker.Current.Contact.ContactId);
}
}
}
ContactIdentificationRepository
using System.Linq;
using Sitecore.Analytics;
using Sitecore.Analytics.Model;
using Sitecore.Analytics.Tracking;
using Sitecore.Configuration;
using Sitecore.XConnect;
using Sitecore.XConnect.Client.Configuration;
namespace Sitecore.Foundation.Accounts.Repositories
{
public class ContactIdentificationRepository
{
private readonly ContactManager contactManager;
public ContactManager Manager => contactManager;
public ContactIdentificationRepository()
{
contactManager = Factory.CreateObject("tracking/contactManager", true) as ContactManager;
}
public IdentifiedContactReference GetContactReference()
{
// get the contact id from the current contact
var id = GetContactId();
// if the contact is new or has no identifiers
var anon = Tracker.Current.Contact.IsNew || Tracker.Current.Contact.Identifiers.Count == 0;
// if the user is anon, get the xD.Tracker identifier, else get the one we found
return anon
? new IdentifiedContactReference(Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource, Tracker.Current.Contact.ContactId.ToString("N"))
: new IdentifiedContactReference(id.Source, id.Identifier);
}
public Analytics.Model.Entities.ContactIdentifier GetContactId()
{
if (Tracker.Current?.Contact == null)
{
return null;
}
if (Tracker.Current.Contact.IsNew)
{
// write the contact to xConnect so we can work with it
this.SaveContact();
}
return Tracker.Current.Contact.Identifiers.FirstOrDefault();
}
public void SaveContact()
{
// we need the contract to be saved to xConnect. It is only in session now
Tracker.Current.Contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
this.contactManager.SaveContactToCollectionDb(Tracker.Current.Contact);
}
public IXdbContext CreateContext()
{
return SitecoreXConnectClientConfiguration.GetClient();
}
}
}
my question is how to pass username and password from the C# client(xamarin forms) to server's API? if details are correct then the client will get whole product list from webapi(URL).and bind all the details to a listview.I want to get the member details after the success of response code.
the client will send username password from login page to server's API. if server's webapi check whether the details matched with the database, if not, don't let it get product list.
here is the code in loginservices for login(xamarin forms)
public async Task GetData(string username,string password)
{
//string detail = new UserDetails();
UserDetails userDetails = new UserDetails();
// List<UserDetails> detail = new List<UserDetails>();
try
{
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("Username", username));
values.Add(new KeyValuePair<string, string>("Password", password));
var content = new FormUrlEncodedContent(values);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("nl-NL"));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsync("http://192.168.1.50/Accounts/Authenticate", content);
return response.IsSuccessStatusCode;
};
}
catch (Exception ex)
{
throw ex;
}
}
here is the code for web api---
public async Task ValidateUser([FromBody] Credentials credentials)
{
using (DemoAPPEntities entities = new DemoAPPEntities())
{
var result = await entities.MemberDetails.Where(x => x.UserName == credentials.UserName && x.Password == credentials.Password).SingleOrDefaultAsync();
if (result == null)
{
return NotFound();
}
return Ok(entities.MemberDetails);
}
}
(Using ASP.NET Identity 2.1, Microsoft.Owin.Security.Facebook 3.0.1 in a Web API project)
From here: https://developers.facebook.com/docs/facebook-login/login-flow-for-web/v2.2
This is because once someone has declined a permission, the Login Dialog will not re-ask them for it unless you explicitly tell the dialog you're re-asking for a declined permission.
You do this by adding the auth_type: rerequest flag to your FB.login() call:
FB.login(
function(response) {
console.log(response);
},
{
scope: 'user_likes',
auth_type: 'rerequest'
}
);
When you do that, the Login Dialog will re-ask for the declined permission. The dialog will look very much like the dialog in the section on re-asking for permissions but will let you re-ask for a declined permission.
So, using ASP.NET Identity's integration with Facebook login, I know how to pass in the requested scope, but if the user declines the permission, I need to pass in the extra parameter "auth_type" : 'rerequest." How do I do that?
You first add your custom FacebookAuthenticationProvider
public class FacebookProvider : FacebookAuthenticationProvider
{
public override void ApplyRedirect(FacebookApplyRedirectContext context)
{
//To handle rerequest to give some permission
string authType = string.Empty;
if (context.Properties.Dictionary.ContainsKey("auth_type"))
{
authType = string.Format("&auth_type={0}", context.Properties.Dictionary["auth_type"]);
}
//If you have popup loggin add &display=popup
context.Response.Redirect(string.Format("{0}{1}{2}", context.RedirectUri, "&display=popup", authType));
}
}
now in the startup you need to use this provider
var options = new FacebookAuthenticationOptions
{
AppId = "appid",
AppSecret = "secret",
Provider = new FacebookProvider
{
OnAuthenticated = async context =>
{
foreach (var x in context.User)
{
if (x.Key == "birthday")
{
context.Identity.AddClaim(new Claim("dateofbirth", x.Value.ToString()));
}
else
{
context.Identity.AddClaim(new Claim(x.Key, x.Value.ToString()));
}
}
context.Identity.AddClaim(new Claim("fb_accecctoken", context.AccessToken));
await Task.FromResult(context);
}
}
};
options.Scope.Add("public_profile");
options.Scope.Add("email");
options.Scope.Add("user_birthday");
options.Scope.Add("user_location");
app.UseFacebookAuthentication(options);
and finally in your account controller you need to set auth_type when you need
private const string XsrfKey = "xsrfkey";
internal class ChallengeResult : HttpUnauthorizedResult
{
public ChallengeResult(string provider, string redirectUri)
: this(provider, redirectUri, null, false)
{
}
public ChallengeResult(string provider, string redirectUri, string userId, bool isRerequest)
{
LoginProvider = provider;
RedirectUri = redirectUri;
UserId = userId;
IsRerequest = isRerequest;
}
public string LoginProvider { get; set; }
public string RedirectUri { get; set; }
public string UserId { get; set; }
public bool IsRerequest { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
if (IsRerequest)
{
properties.Dictionary["auth_type"] = "rerequest";
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
}
I had the same issue when I wanted to ensure the user had accepted all my permissions. As you probably know this can be detected by calling the /me/permissions url.
So I eventually solved it by simply deleting my app from the user's account.
You can do so by doing a DELETE request on the /me/permissions URL as documented here.
This will remove all permissions you requested from the user, so next time you try authenticating him through Facebook, the prompt appears again.
I am going to write a small program that query Amazon web service for book information.
Given some sample I found online, I wrote;
namespace TestWCF
{
class Program
{
static void Main(string[] args)
{
Console.Write("Enter keyword: ");
var line = Console.ReadLine();
if (line == null)
{
return;
}
using (var svc = new AmazonSearchPortClient())
{
var keywordReq = new KeywordRequest
{
locale = "us",
type = "lite",
sort = "reviewrank",
mode = "books",
keyword = line,
tag = "associate-id",
devtag = "????????????"
};
var productInfo = svc.KeywordSearchRequest(keywordReq);
foreach(var detail in productInfo.Details)
{
Console.WriteLine(detail.ProductName);
}
}
}
}
This does not work as it returns authenticate failure at the line;
var productInfo = svc.KeywordSearchRequest(keywordReq);
I am not sure what information I should put into the tag and devtag fields. Someone says I should put associate ID but what I shall put into the devtag?
Many thanks,
Regards.
}