User not detected as being logged in until '/login' url is hit
I'm using the Play! Framwork with the standard Secure module. What i am seeing, is when a user logs in, and checks remember me, everything works fine. If they close the browser window, re-open and go back to the page, the user is not logged in anymore, but if they goto the default login url '/login', it automatically logs them in and redirects back to the home page with the user correctly being show as logged in.
What is going wrong that the user has to hit the login url for the site to detect they are logged in? Am i missing something in my controller to do this?
Here is the controller in question, and my custom 开发者_StackOverflow社区Security class:
public class Main extends Controller {
@Before
public static void checkUser() {
String user = Security.connected();
boolean connected = Security.isConnected();
renderArgs.put("isConnected", connected);
if (!connected) return;
User u = User.findUser(user);
String displayName = u.firstName + " " + u.lastName;
renderArgs.put("displayName", displayName);
}
public static void homePage() {
List<Testimonial> testimonials = Testimonial.findAll();
List<News> news = News.findAll();
Twitter twitter = new TwitterFactory().getInstance();
List<TweetView> tweets = new ArrayList<TweetView>();
try {
List<Status> result = twitter.getUserTimeline("atmospherian");
for (Status s: result) {
String source = s.getSource();
String content = s.getText();
tweets.add(new TweetView(source, content));
}
} catch (TwitterException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
if (tweets.size() > 0) {
tweets = tweets.subList(0, 3);
}
render(testimonials, news, tweets);
}
}
public class Security extends Secure.Security {
static boolean authenticate(String username, String password) {
User user = User.find("byEmail", username).first();
return user != null && user.password.equals(Crypto.passwordHash(password));
}
static boolean check(String profile) {
if ("admin".equals(profile)) {
return User.find("byEmail", connected()).<User>first().isAdmin;
}
return false;
}
}
Now that we've established that you're not using @With(Secure.class)
on this controller I've got a different answer. Secure
's checkAccess
method doesn't get called in this case. You could add this method to your controller:
private static void loadCookieIfPresent() {
Http.Cookie remember = request.cookies.get("rememberme");
if (remember != null && remember.value.indexOf("-") > 0) {
String sign = remember.value.substring(0, remember.value.indexOf("-"));
String username = remember.value.substring(remember.value.indexOf("-") + 1);
if (Crypto.sign(username).equals(sign)) {
session.put("username", username);
}
}
}
and call it in the beginning of your checkUser
method to read the cookie without forcing a login.
I suspect this is because the login check is also triggered using a @Before
annotation, so they may be executing in the wrong order:
public class Secure extends Controller {
@Before(unless={"login", "authenticate", "logout"})
static void checkAccess() throws Throwable {
// Authent
if(!session.contains("username")) {
flash.put("url", request.method == "GET" ? request.url : "/"); // seems a good default
login();
}
...
I'm not sure if the ordering is even defined for multiple @Before
methods. Quick fix would be to remove the @Before
from checkUser
and just call it at the beginning of your homePage
method.
精彩评论