c# - 从模型中传递数据
问题描述
我目前正在使用 Salesforce API 填充数据。
在我的帐户控制器中,我有一个使用 Salesforce 用户名/密码流来授权 API 使用的方法,我已经附加了这个方法,以便它在登录时执行此操作,这个过程很好,它可以工作并且我已经对其进行了测试。
但是在我的问题出现的地方,我需要访问它在登录时生成的 AccessToken 值和 ServiceUrl 值,以便我可以在另一个控制器中使用我的“GetEvents”方法。
目前我正在使用模型,根本没有数据上下文,因为我不需要它。但是,如果我要在我的另一个控制器中使用 AccessToken 属性来实例化此模型,则该值将不会从生成此 Token 的控制器方法传递。
请记住,这些方法工作得很好,但我需要获得授权才能查看任何这些事件,如果它没有来自登录方法的 AccessToken 和 ServiceUrl,我将无法查看任何事件。
我该怎么做?
HomeController 中的方法
public async void GetAllEvents()
{
TokenModel tm = new TokenModel();
HttpClient queryClient = new HttpClient();
string restQuery = tm.ServiceUrl + "/services/data/v25.0/query?q=SELECT+Subject+from+Event";
Console.WriteLine(restQuery);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, restQuery);
Console.WriteLine(request);
// Adding the token to the header
request.Headers.Add("Authorization", "Bearer " + tm.AccessToken);
// Return JSON to the caller
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Call Endpoint Async
HttpResponseMessage response = await queryClient.SendAsync(request);
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
AccountController 中的方法
[HttpPost]
[AllowAnonymous]
public IActionResult Login(AuthRequestModel authRequest)
{
if (!ModelState.IsValid)
{
return View(authRequest);
}
if(authRequest == null)
{
return BadRequest("Authorization is missing");
}
var isAuth = Authentication.ActiveDirectoryValidation(authRequest.Username, authRequest.Password);
if(isAuth == true)
{
AuthR().Wait();
return RedirectToAction("Index", "Home");
}
return View();
}
// Salesforce Username / Password Validation
public async Task<string> AuthR()
{
TokenModel tm = new TokenModel();
var handler = new HttpClientHandler()
{
SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
};
HttpClient authClient = new HttpClient(handler);
string clientId = _config.GetSection("Keys").GetSection("client_id").Value;
string clientSecret = _config.GetSection("Keys").GetSection("client_secret").Value;
string username = _config.GetSection("Keys").GetSection("username").Value;
string password = _config.GetSection("Keys").GetSection("password").Value;
HttpContent content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{"grant_type","password"},
{"client_id",clientId},
{"client_secret",clientSecret},
{"username",username},
{"password",password}
}
);
HttpResponseMessage message = await
authClient.PostAsync("https://test.salesforce.com/services/oauth2/token", content);
string responseString = await message.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseString);
tm.AccessToken = model["access_token"];
tm.ServiceUrl = model["instance_url"];
return tm.AccessToken;
}
解决方案
我不是 C# 人,但可能你应该有一个单独的类来进行新的登录调用或重用现有的会话 ID。可以是静态方法,也可以是单例模式(在 C# 中使用合适的词);如果从另一个模型(线程?)调用静力学行为正常。在一些全局变量中共享会话 ID 可能也可以正常工作,但有点臭。
也许您必须将会话 ID 存储在某处(如果您没有可用的内存缓存,那么可能是文件?数据库?),加密与否。
经过实战考验的登录 SF 模式看起来有点像这样
do we have cached session id?
no -> call login()
-> it worked? great, cache new session id somewhere
-> didn't work (account deactivated, password expired, network problems) - you have bigger problems your program probably can't recover from nicely, notify user? There's way to reset password via API but it's bit "pro"
yes -> try to use it
-> worked? great
-> error? check the details / HTTP error code and if it's for example session id expired - call new login & handle it like above
根据身份验证方法,您将在会话 id 即将到期时获得信息(例如,从现在起 2 小时,但每次 API 使用都会重置计数器)。不要过分指望这 2 小时。SF 管理员可以随时终止您的会话(例如防止黑客访问)。或者对于相同的凭据可以打开的会话有限制,曾经类似于第 5 次 login() 调用使最旧的会话 ID 无效。