Domanda

I have an application that uses GWTP, which heavily relies on Gin & Guice. My app authentication works using a CurrentUserDto to represent the currently logged in user, which is bound to a Provider and is injected where needed.

My app allows users to login by checking the user's email and password against the datastore and sets a token in the user's cookies if there is a match, to signify being logged in. Pretty basic stuff so far...

The CurrentUserDtoProvider checks for the cookie on the client, and if it exists and is still valid, returns the CurrentUserDto with the correct details.

My LoginPresenter:

public class LoginPresenter extends Presenter<LoginPresenter.MyView, LoginPresenter.MyProxy> implements LoginUiHandlers
{
private CurrentUserDto currentUserDto;

public interface MyView extends View, HasUiHandlers<LoginUiHandlers>
{
}

@Title("Login")
@NoGatekeeper
@ProxyStandard
@NameToken(NameTokens.login)
public interface MyProxy extends ProxyPlace<LoginPresenter>
{
}

private DispatchAsync dispatchAsync;
private PlaceManager placeManager;

@Inject
public LoginPresenter(EventBus eventBus, MyView view, MyProxy proxy,
    DispatchAsync dispatchAsync, PlaceManager placeManager,
        CurrentUserDto currentUserDto)
{
    super(eventBus, view, proxy, RevealType.Root);

    this.dispatchAsync = dispatchAsync;
    this.placeManager = placeManager;
    this.currentUserDto = currentUserDto;

    getView().setUiHandlers(this);
}

@Override
protected void onReveal()
{
    if(currentUserDto.isLoggedIn())
    {
        System.out.println("User IS logged in - redirecting to main page");
        PlaceRequest request = new PlaceRequest.Builder().nameToken(NameTokens.home).build();
        placeManager.revealPlace(request, true);
    }
    else
    {
        System.out.println("User IS NOT logged in - showing login page");
        // do nothing, we are already on the login page
    }

}

@Override
public void onLoginClick(final String email, String password)
{
    Window.alert("Client logging in as " + email + " with password " + password);

    ClientLogin action = new ClientLogin(email, password);

    dispatchAsync.execute(action, new AsyncCallbackImpl<ClientLoginResult>()
    {
        @Override
        public void onReturn(ClientLoginResult result)
        {
            // set the cookie
            Cookies.setCookie("usavtoken", result.getToken());

            // here I would like to do this:
            //placeManager.revealDefaultPlace()

            // but instead I have to do this:
            // browser refresh workaround, reloads whole app
            String newURL = Window.Location.getHref();
            Window.Location.assign(newURL);

        }
    });

}

}

My problem occurs when my ClientLogin action returns with the validation token. See above onReturn() method. Here I would like to simply run the code in onReveal() again, but as the CurrentUserDto still says a user is not logged in, the login page is left on the screen.

Refreshing the whole GWT app is the only way I can manage to refresh the details in the CurrentUserDto entity that was injected into the login page BEFORE the user logged in. What is the best way to do this?

Is there another way to get a fresh copy of the CurrentUserDto?

Is there another way to reload the same page that will cause Gin to @Inject my constructor again?

Apologies if this is unclear. I am not very experienced with GIN/Guice.

È stato utile?

Soluzione

You're setting cookies and forwarding to different URL's. This is not necessary with GWT or GWTP. No need for the classic postback mindset.

Use the @LoggedInGatekeeper on your pages to control access for logged in/out status. Cookies should be set on the server request for auth and cleared on logout request. @LoggedInGatekeeper implementation wired by Gin should track the user object for the current logged in user if you need it.

Here are the steps I use in my apps

On (app) page load

  1. Make request to server, am I already logged in?
  2. If already logged in, fetch the current user object (can be returned in 1)
  3. Set user object in LoggedInGatekeeper and set logged in state as true

LoggedInGatekeepr will do the rest for you now. If they're requesting an internal page and they are logged out, it will forward them to the specified default place, typically the login screen.

On Login

  1. Dispatch credentials to server
  2. If valid, create valid user session on server and return user object (same as 2 above)
  3. Store user object and login status in LoggedInGatekeeper
  4. Forward to next Place you want user to visit

On Logout

  1. Dispatch request to server
  2. Server invalidated session and clears cookies
  3. Clear LoggedInGatekeeper login status and user object
  4. Forward user to a logged out Place

So, again, no need to even touch cookies on the client side. Don't couple your client with the cookies. Cookies add overhead to every request and couple your client and server code. The server knows how to handle sessions, so let it take care of them.

Altri suggerimenti

You should bind(CurrentUserDto.class).in(Singleton.class), and set currentUserDto.setLoggedIn(true) within the onReturn method.

What about not binding the CurrentUserDto as a Singleton? You should get a fresh instance on every currentUserDtoProvider.get() then!

You would need to inject the CurrentUserDtoProvider then in the presenters as they are singletons and not keep a reference on the CurrentUserDto but always call currentUserDtoProvider.get() when you need to check the logged in user.

It would be helpful to see the provider code, too, by the way.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top