Xem mẫu

CHAPTER 6 AUTHENTICATING USERS LoginInfo Class This class is a simple POJO returned by the User service when a user has successfully logged in using the Google Accounts service. The LoginInfo class is implemented in Listing 6-2. Listing 6-2. The code for LoginInfo.class package com.appirio.timeentry.client; import java.io.Serializable; public class LoginInfo implements Serializable { private boolean loggedIn = false; private String loginUrl; private String logoutUrl; private String emailAddress; private String nickname; public boolean isLoggedIn() { return loggedIn; } public void setLoggedIn(boolean loggedIn) { this.loggedIn = loggedIn; } public String getLoginUrl() { return loginUrl; } public void setLoginUrl(String loginUrl) { this.loginUrl = loginUrl; } public String getLogoutUrl() { return logoutUrl; } public void setLogoutUrl(String logoutUrl) { this.logoutUrl = logoutUrl; 128 CHAPTER 6 AUTHENTICATING USERS } public String getEmailAddress() { return emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } } LoginService and LoginServiceAsync Interfaces Now you need to create two interfaces defining your login service and its methods. In Listing 6-3 notice the “login” path annotation in the LoginService class. You’ll configure this path in the deployment descriptor to map the configuration to this service. Listing 6-3. The code for LoginService.class package com.appirio.timeentry.client; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @RemoteServiceRelativePath("login") public interface LoginService extends RemoteService { public LoginInfo login(String requestUri); } Next, you need to add an AsyncCallback parameter to your service method. Your interface in Listing 6-4 must be located in the same package as the service interface and must also have the same name but appended with Async. Each method in this interface must have the same name and signature as in the service interface 129 CHAPTER 6 AUTHENTICATING USERS however, the method has no return type and the last parameter is an AsyncCallback object. Listing 6-4. The code for LoginServiceAsync.class package com.appirio.timeentry.client; import com.google.gwt.user.client.rpc.AsyncCallback; public interface LoginServiceAsync { public void login(String requestUri, AsyncCallback async); } Google Accounts Login Implementation Now you need to create your server-side implementation (Listing 6-5) that uses Google Accounts to actually authenticate your users and return their information if successful. Listing 6-5. The code for LoginServiceImpl.class package com.appirio.timeentry.server; import com.google.appengine.api.users.User; import com.google.appengine.api.users.UserService; import com.google.appengine.api.users.UserServiceFactory; import com.appirio.timeentry.client.LoginInfo; import com.appirio.timeentry.client.LoginService; import com.google.gwt.user.server.rpc.RemoteServiceServlet; public class LoginServiceImpl extends RemoteServiceServlet implements LoginService { public LoginInfo login(String requestUri) { LoginInfo loginInfo = new LoginInfo(); UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); if (user != null) { loginInfo.setLoggedIn(true); loginInfo.setLogoutUrl(userService.createLogoutURL(requestUri)); 130 CHAPTER 6 AUTHENTICATING USERS loginInfo.setNickname(user.getNickname()); loginInfo.setEmailAddress(user.getEmail()); } else { loginInfo.setLoggedIn(false); loginInfo.setLoginUrl(userService.createLoginURL(requestUri)); } return loginInfo; } } Modifying the Deployment Descriptor In your LoginService class you defined the “login” path annotation. Now you need to add this definition to the deployment descriptor in Listing 6-6. You can also remove the reference to greetServlet since it is not needed. Listing 6-6. Servlet configuration to be added to the deployment descriptor loginService com.appirio.timeentry.server.LoginServiceImpl loginService /timeentry/login Modifying the User Interface Now that your login RPC framework is in place, you need to tweak the client to allow it to use your new authentication functionality. Currently, when your users load the application, your timecard UI is immediately available. You need to change the flow of the application to load the timecard UI if the user is already logged in or to redirect them to the sign-in page if they are not. Once they sign-in with their Google account, you’ll still need to make a check to ensure that they are indeed authenticated. You’ll need to do some refactoring in TimeEntry.java to accomplish these tasks. In Listing 6-7 you’ll move the call to load the UI from the onModuleLoad method to a new 131 CHAPTER 6 AUTHENTICATING USERS private method. You’ll then add a new panel that displays the login form and modify onModuleLoad to display this panel conditionally. First, rename the current onModuleLoad method to “loadMainUI” and make it private. Now add the following imports and methods to TimeEntry.java. Listing 6-7. Changes to TimeEntry.java import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.rpc.AsyncCallback; public void onModuleLoad() { logo.setUrl("images/appiriologo.png"); LoginServiceAsync loginService = GWT.create(LoginService.class); loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback() { public void onFailure(Throwable error) { } public void onSuccess(LoginInfo result) { loginInfo = result; if(loginInfo.isLoggedIn()) { loadMainUI(); } else { loadLoginUI(); } } }); } private void loadLoginUI() { VerticalPanel loginPanel = new VerticalPanel(); Anchor loginLink = new Anchor("Sign In"); loginLink.setHref(loginInfo.getLoginUrl()); loginPanel.add(logo); loginPanel.add(new Label("Please sign-in with your Google Account to access the Time Entry application.")); loginPanel.add(loginLink); RootPanel.get("timeentryUI").add(loginPanel); } 132 ... - tailieumienphi.vn