c# web-api value of custom attribute property - c#

Currently I'm working on a C# WebApi.
I made my own TokenAuthorizationAttribute, which checks if the string in the "Authorization"-Header matches the string in a Database.
This works just fine, I can decorate controllers and methods with the attribute and it works.
However now I'm trying to write a method that uses the passed token. Of course i could read out the header again, but i don't want to do that because it needs time (and the method has to work fast). I thought of maybe saving the token to a property of the TokenAuthorizationAttribute, but how can i get the value of it in my method?
Here's the code of my Attribute:
public class TokenAuthorizationAttribute : AuthorizationFilterAttribute {
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) {
public string Token {get; set;}
IEnumerable<string> values;
if (actionContext.Request.Headers.TryGetValues("Authorization", out values)) {
string token = values.FirstOrDefault();
string auth = String.Empty;
SqlConnection conn = SqlService.OpenConnection();
SqlCommand cmd = new SqlCommand("SELECT-Token-Statement", conn);
auth = (string)cmd.ExecuteScalar();
conn.Close();
if (!string.IsNullOrEmpty(auth)) {
Token = auth;
base.OnAuthorization(actionContext);
}
else {
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized) {
ReasonPhrase = "Wrong Token"
};
}
}
else{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized){
ReasonPhrase = "Missing Token"
and my method looks something like that:
[TokenAuthorization]
public static void MyMethod(string value) {
string token = "How do i get the Token?";
}

Related

HttpResponseMessage post API json format with C#

I used the HttpResponseMessage Post method to let the mobile terminal verify the account password. I used the following CODE to run successfully, but the POST format must be run like this.
'{"ID":"xxx","Password":"xxx"}'
It need two ' can run, I don't know why.
I can't request a service using the normal POST format on iOS or Android.
The format I want is {"ID":"xxx","Password":"xxx"},without '
[HttpPost]
public HttpResponseMessage Post([FromBody] string DATA)
{
using (appapidataEntities entities = new appapidataEntities())
{
//string controllerName = ControllerContext.RouteData.Values["controller"].ToString();
JObject jo = JObject.Parse(DATA);
string id = jo["ID"].ToString();
string password = jo["Password"].ToString();
var user = entities.USERs.Where(x => x.ID == id && x.Password == password).FirstOrDefault();
var result = new
{
message = "failure"
};
var result2 = new
{
message = "success"
};
if (user == null)
{
return Request.CreateResponse(HttpStatusCode.OK, result);
}
else
{
return Request.CreateResponse(HttpStatusCode.OK, result2);
}
}
}
public partial class USER
{
public string ID { get; set; }
public string Password { get; set; }
}
}
Please have someone with experience to help me, thank you very much.
As #Nkosi said, the correct way to receive a complex object is using a class/object (also called 'model binding')
In your models add this class. This class will be the 'contract' between the service with any external application who calls the service. Usually, any client (service, app or frontend) also has a class with this contract to call the service.
public class LoginViewModel {
public string ID { get; set; }
public string Password { get; set; }
}
Now, modify the controller as follow
[HttpPost]
public HttpResponseMessage Post([FromBody] LoginViewModel DATA) {
using (appapidataEntities entities = new appapidataEntities())
string id = DATA.ID;
string password = DATA.Password;
// rest of the code
}
}
Make sure the device is sending the data the service is waiting (maybe adding a breakpoint if you are debugging from Android Studio before to make the request) and add a breakpoint in your controller to verify that the variable DATA has the correct values.

Creating Custom AuthorizeAttribute in Web API (.Net Framework)

I'm using OAuth2.0 Owin (password grant) in my WebAPI.My initial token Response is like below
{
"access_token": "_ramSlQYasdsRTWEWew.....................",
"token_type": "bearer",
"expires_in": 17999,
"permissions": {
"user": [
"Add",
"Update",
"Delete"
],
"Product": [
"Read",
"Create"
]
}
}
I've customized the response by creating a new Key called permissions which hold the privileges for the corresponding user.
From here I need to validate each Request from my Resource server,by checking whether the user has enough permissions to call the API using Authorize Attribute.
I found a similar example from here where it deals with Dot net Core, which is not suitable for my case.
The difficult part is that the permission JSON Key is itself making a complex with ArrayList
[CustomAuthorize(PermissionItem.Product, PermissionAction.Read)]
public async Task<IActionResult> Index()
{
return View(Index);
}
public class CustomAuthorize : AuthorizeAttribute {
public AuthorizeAttribute (PermissionItem item, PermissionAction action) {
//Need to initalize the Permission Enums
}
public override void OnAuthorization (HttpActionContext actionContext) {
//Code to get the value from Permissions ArrayList and compare it with the Enum values
}
}
The above is the idea I'm having. But due to the complexity of the Permissions Key and Enum comparison I'm couldn't able to move forward.
Also, there is a question like If the permission for User is Add as well as Update means I need to create two Attribute conditions before my Controller.
Like
[CustomAuthorize(PermissionItem.User, PermissionAction.Add)]
[CustomAuthorize(PermissionItem.User, PermissionAction.Update)]
Which leads to adding more lines of Attributes. So Is there is any way to make it as in a single Conditions with | separated?
[CustomAuthorize(PermissionItem.User, PermissionAction.Update|PermissionAction.Add)]
Why don't you allow your CustomAuthorize constructor to have multiple Permission actions.
public class CustomAuthorize : AuthorizeAttribute
{
private readonly PermissionAction[] permissionActions;
public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
{
this.permissionActions = permissionActions;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
var currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
if (!currentIdentity.IsAuthenticated) {
// redirect to access denied page
}
var userName = currentIdentity.Name;
// step 1 : retrieve user object
// step 2 : retrieve user permissions
// step 3 : match user permission(s) agains class/method's required premissions
// step 4 : continue/redirect to access denied page
}
}
And you'll annotate your class with:
[CustomAuthorize(PermissionItem.User, PermissionAction.Update, PermissionAction.Add)]
I'm not sure, what does OP want to achieve here. If you are relying on HTTP request to provide access rights then that is A BIG SECURITY HOLE. On each request you should retrieve user's access right information from the database and then match is against the required permission of the class/method.
As a rule of thumb you should not rely on request object to tell you what are the permissions that current user have. You should retrieve them from the datastore.
My Implementation of CustomAttribute
public class CustomAuthorize : System.Web.Http.AuthorizeAttribute
{
private readonly PermissionAction[] permissionActions;
public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
{
this.permissionActions = permissionActions;
}
protected override Boolean IsAuthorized(HttpActionContext actionContext)
{
var currentIdentity = actionContext.RequestContext.Principal.Identity;
if (!currentIdentity.IsAuthenticated)
return false;
var userName = currentIdentity.Name;
using (var context = new DataContext())
{
var userStore = new UserStore<AppUser>(context);
var userManager = new UserManager<AppUser>(userStore);
var user = userManager.FindByName(userName);
if (user == null)
return false;
foreach (var role in permissionActions)
if (!userManager.IsInRole(user.Id, Convert.ToString(role)))
return false;
return true;
}
}
}
You could make us of flags and binary operations to allow you to | the different operations together.
The following code shows a small example of how it could be done
class Program {
static void Main(string[] args) {
Test test = new Test();
CustomAuthorizeAttribute customAuthorizeAttribute = (CustomAuthorizeAttribute)Attribute.GetCustomAttribute(typeof(Test), typeof(CustomAuthorizeAttribute));
customAuthorizeAttribute.Test();
Console.ReadKey();
}
}
[CustomAuthorize(PermissionActions = PermissionAction.Add | PermissionAction.Delete)]
public class Test {
}
public class CustomAuthorizeAttribute : Attribute {
public PermissionAction PermissionActions { get; set; }
public void Test() {
if ((PermissionActions & PermissionAction.Add) == PermissionAction.Add) Console.WriteLine("Add");
if ((PermissionActions & PermissionAction.Delete) == PermissionAction.Delete) Console.WriteLine("Delete");
if ((PermissionActions & PermissionAction.Update) == PermissionAction.Update) Console.WriteLine("Update");
}
}
public enum PermissionAction {
Add = 1,
Update = 2,
Delete = 4
}
Which yields the following output
We have created below API filter for authentication.
Here, "SecretToken", "MerchantKey" this two key passing in API request. we are validating this two from database using "IsValidMerchant" function.
IsValidMerchant this function direct connect with database table where respective value are store
public void OnAuthorization(AuthorizationFilterContext actionContext)
{
const string secretTokenName = "SecretToken";
const string merchentKeyName = "MerchantKey";
bool isValid = false;
if (!actionContext.Filters.Any(item => item is IAllowAnonymousFilter))
{
CPServiceResponse response = new CPServiceResponse();
var secretToken = actionContext.HttpContext.Request.Headers[secretTokenName].FirstOrDefault();
var merchentKey = actionContext.HttpContext.Request.Headers[merchentKeyName].FirstOrDefault();
isValid = this.IsValidMerchant(merchentKey, secretToken,_productCode);
if (isValid == false)
{
response.Status = (int)HttpStatusCode.Unauthorized;
response.Message = Hegic.Shared.Resource.Common.UnauthorizedRequestError;
actionContext.Result = new JsonResult("")
{
Value = new { Status = response }
};
}
}
}

How can I get information about the user using a token

There is a need to receive user data using a token. Hello. There is a need to receive user data using a token. I have a web api + websockets, websockets connection via a web browser.
var webSocket = new WebSocket(handlerUrl);
//Open connection handler.
webSocket.onopen = function () {
webSocket.send("{\"type\":\"LOGIN\",\"access_token\":\"Bearer HIDDEN\"}");
};
Once connected, I immediately send token.
On the server side, it looks as follows:
public class SocketClientController: ApiController
{
 public HttpResponseMessage Get ()
 {
HttpContext.Current.AcceptWebSocketRequest (new WebSocketHandler ());
return Request.CreateResponse (HttpStatusCode.SwitchingProtocols);
}
<miss>
Socket class:
<miss>
private void Login(string access_token)
{
// here i want get user info
}
public override void OnMessage(string input)
{
dynamic data = JObject.Parse(input);
switch ((string)data.type)
{
case "LOGIN":
Login((string)data.access_token);
break;
}
}
I use Identity, a variant with a token when you first received from the client suits me the data. Tell me how you can get the user input without going through the login and password, and use [Authorize].
Sorry for my english.
I decided my task! Below is the code:
public class MachineKeyProtector : Microsoft.Owin.Security.DataProtection.IDataProtector
{
private readonly string[] _purpose =
{
typeof(OAuthAuthorizationServerMiddleware).Namespace,
"Access_Token",
"v1"
};
public byte[] Protect(byte[] userData)
{
throw new NotImplementedException();
}
public byte[] Unprotect(byte[] protectedData)
{
return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose);
}
}
Use:
var secureDataFormat = new TicketDataFormat(new Providers.MachineKeyProtector());
AuthenticationTicket ticket = secureDataFormat.Unprotect(access_token);
var userId = ticket.Identity.GetUserId();

ASP.NET How to receive HTTP data from Android app using OkHttp

I am learning android and webservices. I have an android application that sends data using okHttp and I need to ingest that data on my server and put it into the database. I have a little experience calling and getting data from webservices but have never received data.
As I understand it, in ASP.Net I will need to use a HttpHandler and I have seen some examples but they always seem to be returning data per the request. How do you keep the HttpHandler always listening for this particular incoming data?
Here is the code from my sample android application.
public class MainActivity extends Activity {
TextView outputText;
Button sendData;
EditText edtUser, edtPass;
final String URL = "http://serviceapi.skholingua.com/open-feeds/display_received_params.php";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
outputText = (TextView) findViewById(R.id.textView1);
outputText.setMovementMethod(new ScrollingMovementMethod());
sendData = (Button) findViewById(R.id.button1);
edtUser = (EditText) findViewById(R.id.editText1);
edtPass = (EditText) findViewById(R.id.editText2);
sendData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
String userName = edtUser.getText().toString();
String passWord = edtPass.getText().toString();
OkHttpHandler handler = new OkHttpHandler(userName, passWord);
String result = null;
try {
result = handler.execute(URL).get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
outputText.append(result + "\n");
}
});
}
The Class
public class OkHttpHandler extends AsyncTask<String, Void, String> {
OkHttpClient client = new OkHttpClient();
String userName, passWord;
public OkHttpHandler(String userName, String passWord) {
// TODO Auto-generated constructor stub
this.userName = userName;
this.passWord = passWord;
}
#Override
protected String doInBackground(String... params) {
RequestBody formBody = new FormEncodingBuilder()
.add("name", userName)
.add("pass", passWord)
.build();
Request request = new Request.Builder()
.url(params[0]).post(formBody)
.build();
try {
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response.toString());
return response.body().string();
} catch (Exception e) {
}
return null;
}
The URL will be changed to whatever I create on my server. My question is.. What type of data will this be sending? What do I need to create on my server to ingest it?
If anyone has an example that would be very helpful.
Look into Web API.
Example to read a POST to address hxxp://yourdomain/test/[variable]/[variable] and GET to address hxxp://yourdomain/test/[id]. For example:
hxxp://yourdomain/test2/1 will return the string "You requested number 1"
hxxp://yourdomain/test2/2 will return the string "You requested number 2"
Controller:
public class TestController : ApiController {
[Route("test/{username}/{password}")]
[AcceptVerbs("POST")]
public string Post(string username, string password) {
if(username == "user" && password == "pass") { // check user/pass
string data = Request.Content.ReadAsStringAsync().Result;
//do something
return "User is authenticated";
}
}
[Route("test2/{id}")] {
[AcceptVerbs("GET")]
public string GetData(int id) {
return "You requested number " + id;
}
}
In your example above you would call:
hxxp://yourdomain/test/name/pass
And get the response "User is authenticated"

Session getting cleared with Authorize attribute?

I am trying to customize my Authorize attribute so that it redirects the user to appropriate page if he is not authorized.
This is my code till now:
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
public string ErrorMessage { get; set; }
public string WebConfigKey { get; set; }
private const string UnauthorizedAccessMessage = "UnauthorizedAccessMessage";
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
HttpContext.Current.Session["foo"] = "bar";
base.HandleUnauthorizedRequest(filterContext);
if (string.IsNullOrEmpty(WebConfigKey))
throw new ArgumentNullException("WebConfigKey parameter is missing. WebConfigKey should give the actual page/url");
string configValue = ConfigurationManager.AppSettings[WebConfigKey];
if (string.IsNullOrEmpty(configValue))
throw new Exception(WebConfigKey + "'s value is null or empty");
if (!configValue.StartsWith("http"))
HttpContext.Current.Response.Redirect(WebUIUtils.GetSiteUrl() + configValue);
else
HttpContext.Current.Response.Redirect(configValue);
filterContext.Controller.TempData[UnauthorizedAccessMessage] = ErrorMessage;
HttpContext.Current.Session[UnauthorizedAccessMessage] = ErrorMessage;
}
}
Problem is whatever I store in Session or TempData in this method gets lost when the user arrives in some action method in controller after redirect is done from this method. I checked Session.Keys/TempData.Keys etc. But all values are lost. Probably something is happening in base.HandleUnauthorizedRequest(filterContext);. But I guess that calling to base is important.
Can anybody tell me the exact reason of this behavior and how do I prevent it from happening?
Form authorization and Session are distinct concepts for IIS. You can be authorized but your session can be not valid (for example try to restart the application pool).
Try with this custom attribute:
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (filterContext.Result == null)
{
if (filterContext.HttpContext.Session != null )
{
//add checks for your configuration
//add session data
// if you have a url you can use RedirectResult
// in this example I use RedirectToRouteResult
RouteValueDictionary rd = new RouteValueDictionary();
rd.Add("controller", "Account");
rd.Add("action", "LogOn");
filterContext.Result = new RedirectToRouteResult("Default", rd);
}
}
}
}

Categories