Я играю с созданием приложения на Zendesk с использованием Rust. Ниже показана функция ржавчины на стороне сервера, которая вызывается в маршруте
pub fn oktaredirectprocessor(mut cookies: Cookies, code: String, state: String) -> bool {
let cookie_state_string = cookies.get_private("state").unwrap().value().to_string();
println!("cookie retrieved in oktaredirectprocessor is {}", cookie_state_string);
if state != cookie_state_string {
debug!("State did not match");
false
}else if code == ""{
debug!("Code is empty");
false
}else{
let oktarequest: Oktarequest = Oktarequest::new();
let http = reqwest::Client::new();
let config = oidc::discovery::discover(&http, oktarequest.issuer).expect("error in config-discovery-oidc");
let jwks = oidc::discovery::jwks(&http, config.jwks_uri.clone()).expect("error in jwks-discovery-oidc");
let provider = oidc::discovery::Discovered(config);
let client = oidc::Client::new(oktarequest.id, oktarequest.secret, oktarequest.redirect, provider, jwks);
let mut token = client.request_token(&http, code.as_str()).expect("error in request token-oidc");
client.decode_token(&mut token.id_token).expect("error in decode token oidc");
client.validate_token(&token.id_token, Some(cookies.get_private("nonce").unwrap().value()), None).expect("error in validate token oidc"); cookies.add_private(Cookie::new("access_token", token.access_token().to_string()));
true
}
}
Это работает, когда я запускаю localhost прямо с вкладки браузера. Однако поток паникует, если я запускаю приложение из Zendesk. Ниже приведена обратная связь. Я начинающий кодер и не совсем понимаю.
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:214:60
stack backtrace:
0: rust_begin_unwind
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/std/src/panicking.rs:493:5
1: core::panicking::panic_fmt
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/core/src/panicking.rs:92:14
2: core::panicking::panic
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/core/src/panicking.rs:50:5
3: core::option::Option<T>::unwrap
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/core/src/option.rs:386:21
4: app_remote::oktaredirecthandler
at ./src/main.rs:214:28
5: app_remote::rocket_route_fn_oktaredirecthandler
at ./src/main.rs:213:4
6: core::ops::function::Fn::call
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/core/src/ops/function.rs:70:5
7: <F as rocket::handler::Handler>::handle
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/handler.rs:177:9
8: rocket::rocket::Rocket::route
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/rocket.rs:296:27
9: rocket::rocket::Rocket::route_and_process
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/rocket.rs:242:34
10: rocket::rocket::Rocket::dispatch
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/rocket.rs:217:28
11: <rocket::rocket::Rocket as hyper::server::Handler>::handle
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/rocket.rs:82:24
12: hyper::server::Worker<H>::keep_alive_loop
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:340:13
13: hyper::server::Worker<H>::handle_connection
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:282:15
14: hyper::server::handle::{{closure}}
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:242:34
15: hyper::server::listener::spawn_with::{{closure}}
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/listener.rs:50:31
Как ни странно, проблематичный "cookies.get_private("state").unwrap()" работает в другой функции даже при запуске внутри Zendesk. Ниже приведена функция, где она работает
fn oktalogin(mut cookies: Cookies) -> Redirect {
let oktarequest: Oktarequest = Oktarequest::new();
cookies.add_private(Cookie::new("state", oktarequest.state.clone()));
cookies.add_private(Cookie::new("nonce", oktarequest.nonce.clone()));
println!("stored state cookie from random gen is: {}", cookies.get_private("state").unwrap().value().to_string());
let http = reqwest::Client::new();
let config = oidc::discovery::discover(&http, oktarequest.issuer).expect("error in config-discovery-oidc");
let jwks = oidc::discovery::jwks(&http, config.jwks_uri.clone()).expect("error in jwks-discovery-oidc");
let provider = oidc::discovery::Discovered(config);
let client = oidc::Client::new(oktarequest.id, oktarequest.secret, oktarequest.redirect, provider, jwks);
let options = Options{
scope: Some("openid profile email".to_string()),
state: Some(oktarequest.state.clone()),
nonce: Some(oktarequest.nonce.clone()),
..Default::default()
};
let auth_url = client.auth_url(&options);
Redirect::to(auth_url.into_string())
}
Мой груз.томл
[dependencies]
rocket = { version = "0.4.5", features = ["private-cookies"] }
rocket_codegen = "0.4.5"
serde = "1.0.116"
serde_derive = "1.0.116"
diesel = { version = "1.4.5", features = ["postgres"] }
dotenv = "0.15.0"
serde_urlencoded = "0.7.0"
oidc = "0.3.0"
ring = "=0.16.15"
log = "0.4.8"
rand = "0.7.3"
reqwest = "=0.9.24"
inth-oauth2 = "0.16.0"
url = "=1.7.2"
serde_json = "1.0"
console_log = { version = "0.2", features = ["color"] }
[dependencies.rocket_contrib]
version = "*"
default-features = false
features = ["tera_templates", "json"]
@kmdreko спасибо, ты прав. Обработка None, брошенного get_private
, снимает панику. Есть идеи, что может заставить Zendesk не передавать файлы cookie?
Это зависит от вашего тестирования. Я не знаком с Zendesk, но предполагаю, что он размещен в домене, отличном от локального. Файлы cookie зависят от домена, и iframe может иметь отдельный домен. Домен, размещенный на Zendesk, очевидно, не может видеть файлы cookie, используемые localhost. Однако, если oktalogin
(установить файлы cookie) и oktaredirectprocessor
(получить файлы cookie) определенно происходят в одном и том же домене, то я не знаю.
Почему это сработало на локальном хосте, так это то, что cookie остался. Для корректной работы необходимо добавить код, когда cookie не существует, без unwrap()
.
let cookie_state_string = match cookies.get_private("state") {
Ok(v) => v.value().to_string(),
Err(_) => return false,
};
Спасибо, Акихито. Такая обработка позволила избежать паники потоков. Однако файл cookie по-прежнему не сохраняется при запуске из Zendesk. Есть предположения?
Сначала следует вызвать oktalogin
, и cookie будет сохранен. Затем войдите в oktaredirectprocessor
и получите правильный ответ. Но имя ключа «состояние» слишком популярно, чтобы его можно было перекрыть файлом cookie Zendesk, поэтому он может работать, если изменить имя ключа.
Я не удивлен
get_private
в вашем втором примере, учитывая, что вы делаетеadd_private
прямо заранее. Использование.unwrap()
— это грубый инструмент для предположения, что значение существует. Для проверки файлов cookie вам, вероятно, следует избегать их использования и вместо этого решить, чтоoktaredirectprocessor
следует делать, если ожидаемых файлов cookie нет. Тогда ваш вопрос звучит так: «Почему файлы cookie передаются с использованием локального хоста, а не с использованием zendesk»