I'm trying to use Facebook for users authorization via Forms Authentication in ASP.NET MVC.
I'm getting access token from Facebook and user avatar url and pass these data to Controller, all of this is work just fine until the moment when I need to redirect user.
I did tried FormsAuthentication.RedirectFromLoginPage, RedirectToAction, Response.Redict. None of this methods are working as well as no errors.
Here is the controller:
[HttpPost]
public ActionResult Login(string Url, string AccessToken)
{
string username;
string fullname;
var client = new Facebook.FacebookClient(AccessToken);
dynamic result = client.Get("me", new { fields = "username,first_name,last_name" });
if (result.first_name == null | result.last_name == null)
{
username = result.username;
fullname = null;
}
else
{
username = result.username;
fullname = result.first_name + " " + result.last_name;
}
if (UserExist(username) == false)
{
CreateUser(username, Url, fullname);
//FormsAuthentication.SetAuthCookie(username, true);
//return RedirectToAction("Register", "Home");
FormsAuthentication.RedirectFromLoginPage(username, true);
}
else
{
HttpCookie c = Request.Cookies.Get("UserGuid");
if (c == null)
{
c = new HttpCookie("UserGuid")
{
Value = GetUserGuid(User.Identity.Name),
Expires = DateTime.Now.AddYears(1)
};
Response.Cookies.Add(c);
}
if (result.first_name == null || result.last_name == null)
{
username = result.username;
}
else
{
username = result.first_name + " " + result.last_name;
}
try
{
//FormsAuthentication.SetAuthCookie(username, true);
//Response.Redirect(FormsAuthentication.DefaultUrl);
FormsAuthentication.RedirectFromLoginPage(username, true);
}
catch (Exception)
{
throw new Exception();
}
}
return View();
}
You can't do a simple redirect when accessing your action method through AJAX. You need to do a redirect in your JS code by providing a response url from your controller action.
You can simply return a redirect url from your controller and do the following in JS:
$.ajax({
url: url,
data: data,
success: function(resp) {
window.location.href = resp.Url;
}
})
And in your controller:
return Json(new {Url = "/Home/Index"});
Related
I am using this method for Reset Password
public ResetTokenResult DoPasswordResetTokenForChange(string userId, string token)
{
switch (UserManager.FindById(userId))
{
case null:
return ResetTokenResult.UnknownUserId;
case CatalystUser user when ! (user.PasswordInvalidatedByReset ?? false):
return ResetTokenResult.TokenIsExpired;
case CatalystUser user when ! ((user.PasswordResetTokenExpiration ?? DateTime.MinValue) > DateTime.UtcNow):
return ResetTokenResult.TokenIsExpired;
case CatalystUser user when UserManager.VerifyUserToken(user.Id, "ResetPassword", token):
user.PasswordResetTokenExpiration = DateTime.UtcNow.AddDays(-1); // 1-time use. Invalidate now.UserManager.Update(user);
return ResetTokenResult.Success;
default:
return ResetTokenResult.InvalidToken;
}
}
Controller which I am using this method
[RequireHttpsWhenConfigured]
public async Task<ActionResult> Index(PasswordChangePage currentPage,
string userId, string token, string returnUrl = "")
{
var model = new PasswordChangePageViewModel(currentPage);
var isResetPasswordRequest = !string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(token);
if (!isResetPasswordRequest)
{
if (!RequestContext.IsCurrentUserAuthorized())
return Redirect(NavigationService.GetLoginLink());
model.PasswordChangeModel = new PasswordChangeViewModel {ReturnUrl = returnUrl};
model.ReturnUrl = returnUrl;
return View("Index", model);
}
if (RequestContext.IsCurrentUserAuthorized())
{
SignInManager.AuthenticationManager.SignOut();
return Redirect(Request.Url?.AbsoluteUri ?? "~/");
}
var loginLink = NavigationService.GetLoginLink();
var result = UserAccountService.DoPasswordResetTokenForChange(userId,Base64ForUrlDecode(token));
if ((result & ResetTokenResult.Failure) != ResetTokenResult.None)
{
model.ChangeCanProceed = false;
model.ErrorMessage = GetMessageForTokenResult(result);
model.LoginLink = loginLink;
}
else
{
model.PasswordChangeModel = new PasswordChangeViewModel { CurrentPassword = "null", IsResetPassword = true, UserId = userId, ResetPasswordToken = token };
model.ReturnUrl = loginLink;
}
return View("Index", model);
}
When users want to reset their password, they receive an email with a token link and everything works fine. As I know default ASPNET Identity token burns after 1 clicking to link.
My question is what is the best way to implement logic, the token link will burn after 5 clickings to link which is sent to email.
Hi I've looked through a lot of S.O. pages on this subject but mine is a little different. This has nothing to do with an anti-forgery protected login page or users hitting the back button. At our university we use University of Michigan's CoSign as a single-sign-on solution. Users are authenticated through cosign and on success the username is provided by the IIS server in Request.ServerVariables["REMOTE_USER"] and can then be used for authorization, etc.
Here's some code: in global.asax.cs:
Session["username"] = Request.ServerVariables["REMOTE_USER"];
On each page that might use Ajax (in a file Init.js; code from https://blog.alexmaccaw.com/jswebapps-csrf):
$(document).ready(function () {
SetCSRFHeader();
}
function SetCSRFHeader() {
var CSRF_HEADER = 'RequestVerificationToken';
var setCSRFToken = function (securityToken) {
jQuery.ajaxPrefilter(function (options, _, xhr) {
if (!xhr.crossDomain)
xhr.setRequestHeader(CSRF_HEADER, securityToken);
});
};
var theTokenVal = $('#__bothTokens').val();
setCSRFToken(theTokenVal);
}
In _Layout.cshtml:
#Html.AntiForgeryToken()
#{
string cookieToken, formToken, bothTokens;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
bothTokens = cookieToken + ":" + formToken;
}
<input type="hidden" id="__bothTokens" value="#(bothTokens)" />
I also wrote a class that implements IHttpModule to check all POST requests for the included header, parse it and validate it (code from https://security.stackexchange.com/questions/91164/how-to-check-the-origin-header-server-wide-in-iis-to-prevent-csrf):
public class HeaderCheck : IHttpModule
{
public HeaderCheck()
{
}
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
int errCode = 0;
int STATCODE = 403;
string cookieToken = "";
string formToken = "";
if (context.Request.HttpMethod == "POST") // only on POST requests
{
if (context.Request.Headers["Content-Type"] != null)
{
if (context.Request.Headers["Content-Type"] == "application/json;") // JSON check
{
if (context.Request.Headers["RequestVerificationToken"] != null)
{
string tokenHeaders = context.Request.Headers["RequestVerificationToken"];
string[] tokens = tokenHeaders.Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
else
{
errCode = 3;
}
}
else if (context.Request.Headers["Content-Type"].Length >= 19)
{
if (context.Request.Headers["Content-Type"].Substring(0, 19) == "multipart/form-data") // Form check
{
HttpCookie cookie = new HttpCookie("__RequestVerificationToken");
cookie = context.Request.Cookies["__RequestVerificationToken"];
formToken = context.Request.Form["__RequestVerificationToken"];
if (formToken == null) { tokenstr = "form null"; }
if (cookie != null)
{
cookieToken = cookie.Value;
System.Web.Helpers.AntiForgery.Validate(cookieToken, formToken);
}
else // cookie is null
{
errCode = 4;
}
}
}
else // neither acceptable content form
{
errCode = 5;
}
}
else // content type should not be null
{
errCode = 6;
}
if (errCode > 0)
{
try
{
System.Web.Helpers.AntiForgery.Validate(cookieToken, formToken);
}
catch (HttpAntiForgeryException e2)
{
string err = #"Antiforgery tokens not validated" +
"<br><b>Error in: </b>"
+ context.Request.Url.ToString()
+ "<br><b>Error Message: </b>"
+ e2.Message.ToString()
+ "<br><b>Stack Trace:</b><br>"
+ e2.StackTrace.ToString();
EmailContext.sendEmailOnError(err); // sends email to me for debugging
}
}
if (errCode > 0)
{
context.Response.StatusCode = STATCODE;
context.Response.Flush();
context.Response.End();
}
}
}
public void Dispose() { }
}
}
My questions: Why am I getting the error in the title of this question? How does AntiForgeryValidate know that the token was meant for me but somehow the token that's generated is for current user ""? Is there any way I can put the user into the token? I've even tried the advice at Reload AntiForgeryToken after a login to always regenerate the token the first time the user hits the home page (since they're already logged in at that point. Does this have anything to do with developing in visual studio in HTTP but the acceptance environment which is cosign-protected is https? Does it have anything to do with the fact that IIS is configured for Anonymous Authentication? (I think it needs to be to run under cosign).
Thanks for any advice.
EDIT: More and more I think this is due to IIS Anonymous Authentication being the only mode that's enabled. But any other mode requires some sort of second login, and since cosign is THE authentication provider, that doesn't help. So if anyone has any idea how to programmatically insert the user credentials received from cosign into IIS that might be the way forward.
I am trying to redirect to some page after login.
Here is my code
ViewBag.userid = Session[Declaration.sUserID];
var userid = ViewBag.userid;
if (userid == null)
{
Response.Redirect("signin?url=" + Server.UrlEncode(Request.Url.AbsoluteUri));
}
else
{
string ReturnUrl = Convert.ToString(Request.QueryString["url"]);
if (!string.IsNullOrEmpty(ReturnUrl))
{
Response.Redirect(ReturnUrl);//http://localhost:55197/usermanagement
}
else
{
return RedirectToAction("DashBoard");
}
}
return View();
The problem is that it is not redirecting from Response.Redirect part and always calls the same view again and gain.
Someone have an idea why it's happening?
You need to "return" once you call Response.Redirect, otherwise the code will continue and eventually call return View(), which returns the original view back to the caller. e.g.
ViewBag.userid = Session[Declaration.sUserID];
var userid = ViewBag.userid;
if (userid == null)
{
return Redirect("signin?url=" + Server.UrlEncode(Request.Url.AbsoluteUri));
}
else
{
string ReturnUrl = Convert.ToString(Request.QueryString["url"]);
if (!string.IsNullOrEmpty(ReturnUrl))
{
return Redirect(ReturnUrl);//http://localhost:55197/usermanagement
}
else
{
return RedirectToAction("DashBoard");
}
}
return View();
I need to get the user´s facebook profile picture and input it in a crop structure. I´m using Asp.NET MVC, jcrop and the facebook SDK. Untill now i can input files from my computer. I also have a function that access the facebook of the user and returns a session with the user Id, and a GetPhoto function that should return the profile picture. Can someone help me?
I use this code to input the files from the computer:
[ValidateAntiForgeryToken]
public ActionResult _Upload(IEnumerable<HttpPostedFileBase> files)
{
if (files == null || !files.Any()) return Json(new { success = false, errorMessage = "No file uploaded." });
var file = files.FirstOrDefault(); // get ONE only
if (file == null || !IsImage(file)) return Json(new { success = false, errorMessage = "File is of wrong format." });
if (file.ContentLength <= 0) return Json(new { success = false, errorMessage = "File cannot be zero length." });
var webPath = GetTempSavedFilePath(file);
//mistertommat - 18 Nov '15 - replacing '\' to '//' results in incorrect image url on firefox and IE,
// therefore replacing '\\' to '/' so that a proper web url is returned.
return Json(new { success = true, fileName = webPath.Replace("\\", "/") }); // success
}
i tried doing this but the GetPhoto() is returning a null element.
public ActionResult RetornoFb()
{
var _fb = new FacebookClient();
FacebookOAuthResult oauthResult;
if (!_fb.TryParseOAuthCallbackUrl(Request.Url, out oauthResult))
{
// Error
}
if (oauthResult.IsSuccess)
{
dynamic parameters = new ExpandoObject();
parameters.client_id = id;
parameters.redirect_uri = "http://localhost:4323/Avatar/RetornoFb/";
parameters.client_secret = secretkey;
parameters.code = oauthResult.Code;
dynamic result = _fb.Get("/oauth/access_token", parameters);
var accessToken = result.access_token;
Session.Add("FbUserToken", accessToken);
}
else
{
}
//return RedirectToAction("Upload");
HttpPostedFileBase objFile = (HttpPostedFileBase)new MemoryPostedFile(GetPhoto());
var webPath = GetTempSavedFilePath(objFile);
return Json(new { success = true, fileName = webPath.Replace("\\", "/") }); // success
}
public byte[] GetPhoto()
{
try
{
string url = "https://graph.facebook.com/" + GetProfileId() + "?fields=picture.width(480).height(480)";
WebClient webClient = new WebClient();
string response = webClient.DownloadString(url);
dynamic json = JObject.Parse(response);
string urlPicture = json.picture.data.url;
return webClient.DownloadData(urlPicture);
}
catch (Exception)
{
return null;
}
}
Resolved changing my GetPhoto Function. I was having permission issues.
private byte[] GetPhoto()
{
try
{
var _fb = new FacebookClient(Session["FbuserToken"].ToString());
dynamic resultMe = _fb.Get(GetProfileId()+"?fields=picture.width(480).height(480)");
WebClient webClient = new WebClient();
string urlPicture = resultMe.picture.data.url;
return webClient.DownloadData(urlPicture);
}
catch (Exception)
{
return null;
}
}
I am working on c#mvc4 project.I am trying to post messages,link,images and video to facebook via my website.I followed this tutorial http://www.codeproject.com/Articles/569920/Publish-a-post-on-Facebook-wall-using-Graph-API.I am success with first posting,Secondly while posting it throws an error bad request(400) on the code
facebook.GetAccessToken(Session["facebookQueryStringValue"].ToString());
My code snippets are here
Controller
Authentication auth = new Authentication();
public ActionResult Success()
{
if (Request.QueryString["code"] != null)
{
string Code = Request.QueryString["code"];
Session["facebookQueryStringValue"] = Code;
}
if (Session["facebookQueryStringValue"] != null)
{
Facebook facebook = auth.FacebookAuth();
facebook.GetAccessToken(Session["facebookQueryStringValue"].ToString());
FBUser currentUser = facebook.GetLoggedInUserInfo();
IFeedPost FBpost = new FeedPost();
if (Session["postStatus"].ToString() != "")
{
FBpost.Message = Session["postStatus"].ToString();
facebook.PostToWall(currentUser.id.GetValueOrDefault(), FBpost);
//return RedirectToAction("Index");
}
}
return View();
}
public JsonResult PostStatus(string msg)
{
Session["postStatus"] = msg;
Facebook facebook = auth.FacebookAuth();
if (Session["facebookQueryStringValue"] == null)
{
string authLink = facebook.GetAuthorizationLink();
return Json(authLink);
}
if (Session["facebookQueryStringValue"] != null)
{
facebook.GetAccessToken(Session["facebookQueryStringValue"].ToString());
FBUser currentUser = facebook.GetLoggedInUserInfo();
IFeedPost FBpost = new FeedPost();
if (Session["postStatus"].ToString() != "")
{
FBpost.Message = Session["postStatus"].ToString();
facebook.PostToWall(currentUser.id.GetValueOrDefault(), FBpost);
Session["facebookQueryStringValue"] = "";
}
}
return Json("No");
}
Authentication
public class Authentication
{
public Facebook FacebookAuth()
{
//Setting up the facebook object
Facebook facebook = new Facebook();
facebook.AppID = "xxxxxxxxxxxxxxxxxxx";
facebook.CallBackURL = "http://localhost:8088/PostStatus/Success";
facebook.Secret = "xxxxxxxxxxxxxxxxxxx";
//Setting up the permissions
List<FBPermissions> permissions = new List<FBPermissions>() {
FBPermissions.user_about_me, // to read about me
FBPermissions.user_events,
FBPermissions.user_status,
FBPermissions.read_stream,
FBPermissions.friends_events,
FBPermissions.publish_stream
};
//Pass the permissions object to facebook instance
facebook.Permissions = permissions;
return facebook;
}
}
Ajax call
$.ajax({
url: '/PostStatus/PostStatus',
type: 'POST',
data: { msg: msg },
success: function (authLink) {
if (authLink != 'No') {
// window.open(authLink, 'title', 'width=660,height=500,status=no,scrollbars=yes,toolbar=0,menubar=no,resizable=yes,top=60,left=320');
window.location.href = authLink;
}
}
});
Any help on this error is appreciable.I cant see any other tutorial for posting message,link,video,images on facebook in c# mvc4