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
						71e24ff9e6
					
				@ -85,7 +85,7 @@ impl Component for App {
 | 
			
		||||
        }
 | 
			
		||||
        if self.user_info.is_none() {
 | 
			
		||||
            self.route_dispatcher
 | 
			
		||||
                .send(RouteRequest::ReplaceRoute(Route::new_no_state("/login")));
 | 
			
		||||
                .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login)));
 | 
			
		||||
        }
 | 
			
		||||
        true
 | 
			
		||||
    }
 | 
			
		||||
@ -138,7 +138,7 @@ impl App {
 | 
			
		||||
        match &self.user_info {
 | 
			
		||||
            None => {
 | 
			
		||||
                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(url) => {
 | 
			
		||||
@ -148,7 +148,7 @@ impl App {
 | 
			
		||||
                None => {
 | 
			
		||||
                    if *is_admin {
 | 
			
		||||
                        self.route_dispatcher
 | 
			
		||||
                            .send(RouteRequest::ReplaceRoute(Route::new_no_state("/users")));
 | 
			
		||||
                            .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::ListUsers)));
 | 
			
		||||
                    } else {
 | 
			
		||||
                        self.route_dispatcher
 | 
			
		||||
                            .send(RouteRequest::ReplaceRoute(Route::from(
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,7 @@ use yew_form_derive::Model;
 | 
			
		||||
pub struct LoginForm {
 | 
			
		||||
    common: CommonComponentParts<Self>,
 | 
			
		||||
    form: Form<FormModel>,
 | 
			
		||||
    refreshing: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The fields of the form, with the constraints.
 | 
			
		||||
@ -34,6 +35,7 @@ pub struct Props {
 | 
			
		||||
pub enum Msg {
 | 
			
		||||
    Update,
 | 
			
		||||
    Submit,
 | 
			
		||||
    AuthenticationRefreshResponse(Result<(String, bool)>),
 | 
			
		||||
    AuthenticationStartResponse(
 | 
			
		||||
        (
 | 
			
		||||
            opaque::client::login::ClientLogin,
 | 
			
		||||
@ -99,6 +101,14 @@ impl CommonComponent<LoginForm> for LoginForm {
 | 
			
		||||
                    .emit(user_info.context("Could not log in")?);
 | 
			
		||||
                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;
 | 
			
		||||
 | 
			
		||||
    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
 | 
			
		||||
        LoginForm {
 | 
			
		||||
        let mut app = LoginForm {
 | 
			
		||||
            common: CommonComponentParts::<Self>::create(props, link),
 | 
			
		||||
            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 {
 | 
			
		||||
@ -128,63 +147,71 @@ impl Component for LoginForm {
 | 
			
		||||
 | 
			
		||||
    fn view(&self) -> Html {
 | 
			
		||||
        type Field = yew_form::Field<FormModel>;
 | 
			
		||||
        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>
 | 
			
		||||
        if self.refreshing {
 | 
			
		||||
            html! {
 | 
			
		||||
              <div>
 | 
			
		||||
                <img src={"spinner.gif"} alt={"Loading"} />
 | 
			
		||||
              </div>
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            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>
 | 
			
		||||
                  <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 class="input-group">
 | 
			
		||||
                  <div class="input-group-prepend">
 | 
			
		||||
                    <span class="input-group-text">
 | 
			
		||||
                      <i class="bi-lock-fill"/>
 | 
			
		||||
                    </span>
 | 
			
		||||
                  <div class="input-group">
 | 
			
		||||
                    <div class="input-group-prepend">
 | 
			
		||||
                      <span class="input-group-text">
 | 
			
		||||
                        <i class="bi-lock-fill"/>
 | 
			
		||||
                      </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <Field
 | 
			
		||||
                      class="form-control"
 | 
			
		||||
                      class_invalid="is-invalid has-error"
 | 
			
		||||
                      class_valid="has-success"
 | 
			
		||||
                      form=&self.form
 | 
			
		||||
                      field_name="password"
 | 
			
		||||
                      input_type="password"
 | 
			
		||||
                      placeholder="Password"
 | 
			
		||||
                      autocomplete="current-password" />
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <Field
 | 
			
		||||
                    class="form-control"
 | 
			
		||||
                    class_invalid="is-invalid has-error"
 | 
			
		||||
                    class_valid="has-success"
 | 
			
		||||
                    form=&self.form
 | 
			
		||||
                    field_name="password"
 | 
			
		||||
                    input_type="password"
 | 
			
		||||
                    placeholder="Password"
 | 
			
		||||
                    autocomplete="current-password" />
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group mt-3">
 | 
			
		||||
                  <button
 | 
			
		||||
                    type="submit"
 | 
			
		||||
                    class="btn btn-primary"
 | 
			
		||||
                    disabled=self.common.is_task_running()
 | 
			
		||||
                    onclick=self.common.callback(|e: MouseEvent| {e.prevent_default(); Msg::Submit})>
 | 
			
		||||
                    {"Login"}
 | 
			
		||||
                  </button>
 | 
			
		||||
                  <NavButton
 | 
			
		||||
                    classes="btn-link btn"
 | 
			
		||||
                    disabled=self.common.is_task_running()
 | 
			
		||||
                    route=AppRoute::StartResetPassword>
 | 
			
		||||
                    {"Forgot your password?"}
 | 
			
		||||
                  </NavButton>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group">
 | 
			
		||||
                { if let Some(e) = &self.common.error {
 | 
			
		||||
                    html! { e.to_string() }
 | 
			
		||||
                  } else { html! {} }
 | 
			
		||||
                }
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
                  <div class="form-group mt-3">
 | 
			
		||||
                    <button
 | 
			
		||||
                      type="submit"
 | 
			
		||||
                      class="btn btn-primary"
 | 
			
		||||
                      disabled=self.common.is_task_running()
 | 
			
		||||
                      onclick=self.common.callback(|e: MouseEvent| {e.prevent_default(); Msg::Submit})>
 | 
			
		||||
                      {"Login"}
 | 
			
		||||
                    </button>
 | 
			
		||||
                    <NavButton
 | 
			
		||||
                      classes="btn-link btn"
 | 
			
		||||
                      disabled=self.common.is_task_running()
 | 
			
		||||
                      route=AppRoute::StartResetPassword>
 | 
			
		||||
                      {"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.
 | 
			
		||||
    pub fn logout(_request: (), callback: Callback<Result<()>>) -> Result<FetchTask> {
 | 
			
		||||
        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