mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
app: Implement login refresh
This commit is contained in:
parent
ebffc1c086
commit
b54fe9128d
@ -85,7 +85,7 @@ impl Component for App {
|
|||||||
}
|
}
|
||||||
if self.user_info.is_none() {
|
if self.user_info.is_none() {
|
||||||
self.route_dispatcher
|
self.route_dispatcher
|
||||||
.send(RouteRequest::ReplaceRoute(Route::new_no_state("/login")));
|
.send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login)));
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ impl App {
|
|||||||
match &self.user_info {
|
match &self.user_info {
|
||||||
None => {
|
None => {
|
||||||
self.route_dispatcher
|
self.route_dispatcher
|
||||||
.send(RouteRequest::ReplaceRoute(Route::new_no_state("/login")));
|
.send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login)));
|
||||||
}
|
}
|
||||||
Some((user_name, is_admin)) => match &self.redirect_to {
|
Some((user_name, is_admin)) => match &self.redirect_to {
|
||||||
Some(url) => {
|
Some(url) => {
|
||||||
@ -148,7 +148,7 @@ impl App {
|
|||||||
None => {
|
None => {
|
||||||
if *is_admin {
|
if *is_admin {
|
||||||
self.route_dispatcher
|
self.route_dispatcher
|
||||||
.send(RouteRequest::ReplaceRoute(Route::new_no_state("/users")));
|
.send(RouteRequest::ReplaceRoute(Route::from(AppRoute::ListUsers)));
|
||||||
} else {
|
} else {
|
||||||
self.route_dispatcher
|
self.route_dispatcher
|
||||||
.send(RouteRequest::ReplaceRoute(Route::from(
|
.send(RouteRequest::ReplaceRoute(Route::from(
|
||||||
|
@ -15,6 +15,7 @@ use yew_form_derive::Model;
|
|||||||
pub struct LoginForm {
|
pub struct LoginForm {
|
||||||
common: CommonComponentParts<Self>,
|
common: CommonComponentParts<Self>,
|
||||||
form: Form<FormModel>,
|
form: Form<FormModel>,
|
||||||
|
refreshing: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The fields of the form, with the constraints.
|
/// The fields of the form, with the constraints.
|
||||||
@ -34,6 +35,7 @@ pub struct Props {
|
|||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
Update,
|
Update,
|
||||||
Submit,
|
Submit,
|
||||||
|
AuthenticationRefreshResponse(Result<(String, bool)>),
|
||||||
AuthenticationStartResponse(
|
AuthenticationStartResponse(
|
||||||
(
|
(
|
||||||
opaque::client::login::ClientLogin,
|
opaque::client::login::ClientLogin,
|
||||||
@ -99,6 +101,14 @@ impl CommonComponent<LoginForm> for LoginForm {
|
|||||||
.emit(user_info.context("Could not log in")?);
|
.emit(user_info.context("Could not log in")?);
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
Msg::AuthenticationRefreshResponse(user_info) => {
|
||||||
|
self.refreshing = false;
|
||||||
|
self.common.cancel_task();
|
||||||
|
if let Ok(user_info) = user_info {
|
||||||
|
self.common.on_logged_in.emit(user_info);
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,10 +122,19 @@ impl Component for LoginForm {
|
|||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
|
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
LoginForm {
|
let mut app = LoginForm {
|
||||||
common: CommonComponentParts::<Self>::create(props, link),
|
common: CommonComponentParts::<Self>::create(props, link),
|
||||||
form: Form::<FormModel>::new(FormModel::default()),
|
form: Form::<FormModel>::new(FormModel::default()),
|
||||||
|
refreshing: true,
|
||||||
|
};
|
||||||
|
if let Err(e) =
|
||||||
|
app.common
|
||||||
|
.call_backend(HostService::refresh, (), Msg::AuthenticationRefreshResponse)
|
||||||
|
{
|
||||||
|
ConsoleService::debug(&format!("Could not refresh auth: {}", e));
|
||||||
|
app.refreshing = false;
|
||||||
}
|
}
|
||||||
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
@ -128,63 +147,71 @@ impl Component for LoginForm {
|
|||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
type Field = yew_form::Field<FormModel>;
|
type Field = yew_form::Field<FormModel>;
|
||||||
html! {
|
if self.refreshing {
|
||||||
<form
|
html! {
|
||||||
class="form center-block col-sm-4 col-offset-4">
|
<div>
|
||||||
<div class="input-group">
|
<img src={"spinner.gif"} alt={"Loading"} />
|
||||||
<div class="input-group-prepend">
|
</div>
|
||||||
<span class="input-group-text">
|
}
|
||||||
<i class="bi-person-fill"/>
|
} else {
|
||||||
</span>
|
html! {
|
||||||
|
<form
|
||||||
|
class="form center-block col-sm-4 col-offset-4">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">
|
||||||
|
<i class="bi-person-fill"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Field
|
||||||
|
class="form-control"
|
||||||
|
class_invalid="is-invalid has-error"
|
||||||
|
class_valid="has-success"
|
||||||
|
form=&self.form
|
||||||
|
field_name="username"
|
||||||
|
placeholder="Username"
|
||||||
|
autocomplete="username"
|
||||||
|
oninput=self.common.callback(|_| Msg::Update) />
|
||||||
</div>
|
</div>
|
||||||
<Field
|
<div class="input-group">
|
||||||
class="form-control"
|
<div class="input-group-prepend">
|
||||||
class_invalid="is-invalid has-error"
|
<span class="input-group-text">
|
||||||
class_valid="has-success"
|
<i class="bi-lock-fill"/>
|
||||||
form=&self.form
|
</span>
|
||||||
field_name="username"
|
</div>
|
||||||
placeholder="Username"
|
<Field
|
||||||
autocomplete="username"
|
class="form-control"
|
||||||
oninput=self.common.callback(|_| Msg::Update) />
|
class_invalid="is-invalid has-error"
|
||||||
</div>
|
class_valid="has-success"
|
||||||
<div class="input-group">
|
form=&self.form
|
||||||
<div class="input-group-prepend">
|
field_name="password"
|
||||||
<span class="input-group-text">
|
input_type="password"
|
||||||
<i class="bi-lock-fill"/>
|
placeholder="Password"
|
||||||
</span>
|
autocomplete="current-password" />
|
||||||
</div>
|
</div>
|
||||||
<Field
|
<div class="form-group mt-3">
|
||||||
class="form-control"
|
<button
|
||||||
class_invalid="is-invalid has-error"
|
type="submit"
|
||||||
class_valid="has-success"
|
class="btn btn-primary"
|
||||||
form=&self.form
|
disabled=self.common.is_task_running()
|
||||||
field_name="password"
|
onclick=self.common.callback(|e: MouseEvent| {e.prevent_default(); Msg::Submit})>
|
||||||
input_type="password"
|
{"Login"}
|
||||||
placeholder="Password"
|
</button>
|
||||||
autocomplete="current-password" />
|
<NavButton
|
||||||
</div>
|
classes="btn-link btn"
|
||||||
<div class="form-group mt-3">
|
disabled=self.common.is_task_running()
|
||||||
<button
|
route=AppRoute::StartResetPassword>
|
||||||
type="submit"
|
{"Forgot your password?"}
|
||||||
class="btn btn-primary"
|
</NavButton>
|
||||||
disabled=self.common.is_task_running()
|
</div>
|
||||||
onclick=self.common.callback(|e: MouseEvent| {e.prevent_default(); Msg::Submit})>
|
<div class="form-group">
|
||||||
{"Login"}
|
{ if let Some(e) = &self.common.error {
|
||||||
</button>
|
html! { e.to_string() }
|
||||||
<NavButton
|
} else { html! {} }
|
||||||
classes="btn-link btn"
|
}
|
||||||
disabled=self.common.is_task_running()
|
</div>
|
||||||
route=AppRoute::StartResetPassword>
|
</form>
|
||||||
{"Forgot your password?"}
|
}
|
||||||
</NavButton>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
{ if let Some(e) = &self.common.error {
|
|
||||||
html! { e.to_string() }
|
|
||||||
} else { html! {} }
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,6 +227,32 @@ impl HostService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn refresh(_request: (), callback: Callback<Result<(String, bool)>>) -> Result<FetchTask> {
|
||||||
|
let set_cookies = |jwt_claims: JWTClaims| {
|
||||||
|
let is_admin = jwt_claims.groups.contains("lldap_admin");
|
||||||
|
set_cookie("user_id", &jwt_claims.user, &jwt_claims.exp)
|
||||||
|
.map(|_| set_cookie("is_admin", &is_admin.to_string(), &jwt_claims.exp))
|
||||||
|
.map(|_| (jwt_claims.user.clone(), is_admin))
|
||||||
|
.context("Error clearing cookie")
|
||||||
|
};
|
||||||
|
let parse_token = move |data: String| {
|
||||||
|
serde_json::from_str::<login::ServerLoginResponse>(&data)
|
||||||
|
.context("Could not parse response")
|
||||||
|
.and_then(|r| {
|
||||||
|
get_claims_from_jwt(r.token.as_str())
|
||||||
|
.context("Could not parse response")
|
||||||
|
.and_then(set_cookies)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
call_server(
|
||||||
|
"/auth/refresh",
|
||||||
|
yew::format::Nothing,
|
||||||
|
callback,
|
||||||
|
"Could not start authentication: ",
|
||||||
|
parse_token,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// The `_request` parameter is to make it the same shape as the other functions.
|
// The `_request` parameter is to make it the same shape as the other functions.
|
||||||
pub fn logout(_request: (), callback: Callback<Result<()>>) -> Result<FetchTask> {
|
pub fn logout(_request: (), callback: Callback<Result<()>>) -> Result<FetchTask> {
|
||||||
call_server_empty_response_with_error_message(
|
call_server_empty_response_with_error_message(
|
||||||
|
BIN
app/static/spinner.gif
Normal file
BIN
app/static/spinner.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
Loading…
Reference in New Issue
Block a user