Hi I am trying to add a review to a location by an user
I have the following code in my Bll
public void AddReview(Guid locationId, ReviewDto review, UserDto user)
{
var location = _locationRepository.Get(locationId);
var reviewModel = new Review
{
Comment = review.Comment,
Rate = review.Rate,
Location = location,
LocationId = location.Id,
User = new User
{
Name = user.Name,
Email = user.Email,
Password = user.Password
},
UserId = user.Id
};
_reviewRepository.Add(reviewModel);
_reviewRepository.Save();
location.AddReview(reviewModel);
}
}
It's possible to sent User and Review both from Post ?
How U.R.I. should look like .. I think about
/api/location/{id}/review/user (POST)....I don't know , I would appreciate some Help ..Thanks !!
One way of doing this would be POSTing that exact payload at
/api/location/{id}/review
I'd say you'd only use the /user endpoint when accessing that resource, because it would be weird POSTing a review (basically) to the user endpoint. If you're talking about REST level 3, you could have a link from the review to the user. Alternatively you could simply embed the user inside the review resource as to get them both in one call.
That being said, the most orthodox approach would probably adding them in steps (add a review, go to the resource, follow some sort of user-add relationship and POST a user.
Related
Just migrated to Stripe.com. I am creating a checkout session programmatically. See code snippet below. When I test, the User.Identity.GetUserId() comes back with a value and it is sent to stripe. However, when end user completes the payment, Stripe.com is not sending back the client_reference_id (it is null) in the event checkout.session.completed that I am listening to.
I get back my client_reference_id when I do payment links (send via querystring)
What am I doing wrong?
[HttpPost]
[AllowAnonymous]
public ActionResult SendToCheckout(ProcessPaymentViewModel model)
{
StripeConfiguration.ApiKey = _apiSecret;
var options = new SessionCreateOptions
{
ClientReferenceId = User.Identity.GetUserId(),
SuccessUrl = ConfigurationManager.AppSettings["BaseUrl"] + "/PaymentComplete",
CancelUrl = ConfigurationManager.AppSettings["BaseUrl"] + "/Subscribe",
LineItems = new List<SessionLineItemOptions>
{
new SessionLineItemOptions
{
Price = model.PriceId,
Quantity =long.Parse(model.Quantity)
},
},
Mode = "payment",
};
var service = new SessionService();
var session = service.Create(options);
return Redirect(session.Url);
}
reviewed stripe.com documentation. It appears I am setting it correctly. The other questions posted is one is really not answered and the other one says it should be in that webhook event. I dumped the values and it should client_reference_id: null
The code you shared looks correct and it's almost certain that you are not setting a value when you think you are.
The best path forward is to hardcode a value in your code and you should see that it works as expected and that the problem is the value you put in. What I would do is hardcode AAAA, confirm it's there, and then concat AAAA and the value in your variable and another string like AAAA-<userid>-BBBB and see that you get AAAA--BBBB because your string is null or empty.
This isn't a Stripe bug, that feature works as expected and is used widely but I've tested it quickly to confirm.
You can also look at the response on the Session creation after your code and just print session.ClientReferenceId and see that it's null right now.
Hope somebody can help me with this. I am trying to create a Change Password Post Request in the Account controller, but my user is always returning null. I'm new to .NET, could someone help up me figure out the best way to retrive the current user Id? Here is the code I have thus far.
[HttpPost("changePassword")]
public async Task<ActionResult<ChangePasswordDTO>> ChangePassword([FromBody] ChangePasswordDTO changePassword) {
var currentUserId = User.Claims.ToList()
.FirstOrDefault(x => x.Type == "").Value;
var user = await _userManager.FindByIdAsync(currentUserId);
var result = await _userManager.ChangePasswordAsync(user, changePassword.Password, changePassword.NewPassword);
if (result.Succeeded) {
return Ok("Password changed succesfully");
} else return Unauthorized("An error occurred while attempting to change password");
}
When I change the "currentUserId" to a hard coded value, everything works fine, of course. Every user has a generated jwt token with his name, id, roles etc. I'm unsure how to proceed, everything I've tried retrieves the user as null. Let me know if you need extra information, I'm pretty new to all of this and appreciate whatever help I can get, thanks!
Solution
JamesS pointed me in the right direction, this code works:
var currentUserId =this.User.FindFirstValue(ClaimTypes.NameIdentifier);
You can get the current user id in your controller using the UserManager such as:
ASP.NET CORE >= 2.0
var currentUserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
or Name using:
var currentUserId = User.FindFirstValue(ClaimTypes.Name);
If you want to get the current user in some other class, you can use the IHttpContextAccessor, passing it into the class's constructor and using the HttpContext to access the User
I'm working on integrating PayPal into a client's ecommerce site. Using the sandbox, we got everything working fine. I now need to add in SetPaymentOptionsRequest to prevent the user from changing his shipping address (they enter it on our site, so they can't change it at PayPal due to different shipping costs calculated on our site). It appears to work fine, but I get a 3005 error when logging into the PayPal sandbox site to confirm the transaction. Below is the relevant code (C#):
public string MakeChainedPayment(params params) {
var request = new PayRequest {
requestEnvelope = new RequestEnvelope("en_us"),
actionType = "CREATE",
cancelUrl = this._cancelUrl,
currencyCode = this._currencyCode,
returnUrl = this._returnUrl,
ipnNotificationUrl = this._ipnNotificationUrl
};
// Some code to generate receivers, not important for this problem, I don't think
var response = this._paymentService.Pay(request);
switch (response.paymentExecStatus) {
// This always returns "CREATED", as I'd want, so good up to here.
case "CREATED":
// If I leave this code out, PayPal works fine, but I need
// this part to do the shipping address verification.
var p = new SetPaymentOptionsRequest();
p.senderOptions = new SenderOptions();
p.senderOptions.addressOverride = false;
p.senderOptions.shippingAddress = new ShippingAddressInfo {
// Setting from params: city, country, zip, state, street1, street2
};
p.payKey = response.payKey;
p.requestEnvelope = request.requestEnvelope;
SetPaymentOptionsResponse r = _paymentService.SetPaymentOptions(payOptsReq);
break;
// This always retuns r.error.Count = 0, r.responseEnvelope.ack = "SUCCESS",
// so I think I'm good to go.
}
if (this._useSandbox) {
return string.Concat("https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=", response.payKey);
}
return string.Concat("https://www.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=", response.payKey);
}
Paypal returns this message when your Paypal account's email address has not been verified. To verify your Paypal Email account, please follow the following steps:
Log into your Paypal Account. You should be in the “Overview” tab.
Click on your Email address, under “Business account overview”, you will be taken to a Web page listing your Paypal Email addresses.
Select your Primary Adress.
Click on the “Confirm” button.
Follow the rest of the Paypal instructions.
The problem was what I was passing in for the country; I was sending in "USA", and it should be "US".
I am new to webapi and mvc and I am struggling to find a best practice for handling authorizations dynamically based on roles and ownership of the resource. For example an account page that should allow employee admins, employee call center or the owning client to Get, Post, Put or Delete account information. So an admin and call center employee should be able to Get, Post, Put or Delete any request for any userid, but a client should only be able to perform these actions on resources owned by them.
For example Tom is UserID 10 and Jerry is UserID 20.
/api/Account/10 should be accessible by any admin, call center or Tom. Jerry should be kicked out.
/api/Account/20 should be accessible by any admin, call center or Jerry. Tom should be kicked out.
In webforms the typical solution is to just check if the user is a client and verify their id against the request. (I know AuthorizeAttribute is not in webforms, but showing as an example of what it would covert to in webapi/mvc.)
[Authorize(Roles = "Administrator, CallCenter, Client")]
public string Get(int userID)
{
if (Thread.CurrentPrincipal.IsInRole("Client") && Thread.CurrentPrincipal.Identity.userID != userID)
{
//Kick them out of here.
}
return "value";
}
This will work, but it seems like the check for ownership should happen in a single location before it reaches the controller and should be reusable throughout an application. I am guessing the best place would either be a custom AuthorizationFilterAttribute or a custom AuthorizeAttribute and maybe create a new role ClientOwner.
[Authorize(Roles = "Administrator, CallCenter, ClientOwner")]
public string Get(int userID)
{
return "value";
}
Custom AuthorizeAttribute
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
//If user is already authenticated don't bother checking the header for credentials
if (Thread.CurrentPrincipal.Identity.IsAuthenticated) { return; }
var authHeader = actionContext.Request.Headers.Authorization;
if (authHeader != null)
{
if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&
!String.IsNullOrWhiteSpace(authHeader.Parameter))
{
var credArray = GetCredentials(authHeader);
var userName = credArray[0];
var password = credArray[1];
//Add Authentication
if (true)
{
var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null);
var user = GetUser(userName);
foreach (var claim in user.Cliams)
{
currentPrincipal.Identities.FirstOrDefault().AddClaim(new Claim(ClaimTypes.Role, claim);
}
//**************Not sure best way to get UserID below from url.***********************
if (user.userTypeID = UserTypeID.Client && user.userID == UserID)
{
currentPrincipal.Identities.FirstOrDefault().AddClaim(new Claim(ClaimTypes.Role, "ClientOwner"));
}
Thread.CurrentPrincipal = currentPrincipal;
return;
}
}
}
HandleUnauthorizedRequest(actionContext);
}}
Can someone point me in the right direction as to the best place to handle the authorization of the individual user? Should this still be done in the controller or should I move it to a custom AuthorizationFilterAttribute or a custom AuthorizationAttribute or is there somewhere else this should be handled? If the proper place is in a custom attribute, then what is the best way to get the userID and should I create a new role like the example above or should I do something different?
This is a common scenario and I am very surprised that I have struggled to find examples of the above scenario. This leads me to believe that either everyone is doing the check in the controller or there is another term I am not aware of so I am not getting good google results.
I think you may be getting authorization and permissions confused. "Dynamic authorization" isn't something you ever do.
Authorization is the act of verifying an author.
Request claims it is being sent from Alice.
Request presents a password or authorization token that proves the requester is Alice.
Server verifies that the password or authorization token matches its records for Alice.
Permissions are the business logic that specifies who can do what in your system.
Request is already authorized, and we know it came from Alice.
Alice is requesting to delete an important resource.
Is Alice an administrator? If not, tell her she can't do that because she doesn't have permission. (403 Forbidden)
The built-in [Authorize] attribute lets you optionally specify Roles that are permitted to access a resource. That option to specify permissions as part of authorization is slightly misplaced, in my opinion.
My advice would be to leave authorization as purely the process of verifying the author of a request. The BasicAuthHttpModule described here is close to what you want already.
Non-trivial permissions logic needs to be handled inside of your action body. Here's an example:
//Some authorization logic:
// Only let a request enter this action if the author of
// the request has been verified
[Authorize]
[HttpDelete]
[Route("resource/{id}")]
public IHttpActionResult Delete(Guid id)
{
var resourceOwner = GetResourceOwner(id);
//Some permissions logic:
// Only allow deletion of the resource if the
// user is both an admin and the owner.
if (!User.IsInRole("admin") || User.Identity.Name != resourceOwner)
{
return StatusCode(HttpStatusCode.Forbidden);
}
DeleteResource(id);
return StatusCode(HttpStatusCode.NoContent);
}
In this example, it would be difficult to convey the permissions logic as an attribute on the action, because the portion of the permissions that compares the current user to the resource owner can only be evaluated after you have actually gotten the resource owner info from your backend storage device.
Background
Currently, a project I'm on is doing security in a not-so-great way. I'm trying to upgrade it to Claims-based security because I think it matches up better with the type of information we store. However, I'm new to it so trying to soak up a lot ASAP.
We need to store:
Standard info (name, e-mail, etc.)
There are good claimtypes for this already.
A list of client sites the user has access to
presumably a claim type called "ClientSite" with an ID) -- should be simple-ish
A list of roles that users have, per given client site.
Hmm....
That last one is tripping me up a bit. I think I need to create a custom Claim Type that has a client site ID and a role value.
Question
How do I create a custom claim type that would store an ID (representing a section of the site) and the role itself?
Once I've done that, how would I appropriately create that claim? Do I need a custom way to deal with Rights.PossessProperty, or am I overthinking it?
Thanks in advance for pointing me in the right direction. As I said, I'm soaking up Pluralsight courses, etc. but I'd also like to ship something. :)
You are looking at the wrong Claim classes - the one in System.IdentityModel.Claim is deprecated.
The new one is System.Security.Claims.
This book gives you the introduction to the philosophy:
http://msdn.microsoft.com/en-us/library/ff423674.aspx
Let's assume that you will have your "users to sections" coming from a database.
Identity.HasClaim will let you validate the user to section. As far as the custom claim, it's just a string that needs to look similar to the one in the example below.
public class UsersSections
{
public int SectionId { get; set; }
public int UserId { get; set; }
}
var userSectionsList = new List<UsersSections>
{
new UsersSections
{
SectionId = 1000,
UserId = 200
},
new UsersSections
{
SectionId = 2000,
UserId = 200
}
};
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier,"I am a user with a userid of 200"));
foreach (var usersSections in userSectionsList)
{
identity.AddClaim(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/section","1000"));
}
if (identity.HasClaim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/section", "1000"))
{
}