Add support for multiple sessions in a browser
Fixes gh-49
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package sample
|
||||
|
||||
import geb.spock.*
|
||||
import sample.pages.HomePage;
|
||||
import sample.pages.LinkPage;
|
||||
import spock.lang.Stepwise
|
||||
import pages.*
|
||||
|
||||
/**
|
||||
* Tests the demo that supports multiple sessions
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@Stepwise
|
||||
class UserTests extends GebReportingSpec {
|
||||
def 'first visit not authenticated'() {
|
||||
when:
|
||||
to HomePage
|
||||
then:
|
||||
form
|
||||
!username
|
||||
}
|
||||
|
||||
def 'login single user'() {
|
||||
setup:
|
||||
def user = 'rob'
|
||||
when:
|
||||
login(user, user)
|
||||
then:
|
||||
username == user
|
||||
}
|
||||
|
||||
def 'add account'() {
|
||||
when:
|
||||
addAccount.click(HomePage)
|
||||
then:
|
||||
form
|
||||
!username
|
||||
}
|
||||
|
||||
def 'log in second user'() {
|
||||
setup:
|
||||
def user = 'luke'
|
||||
when:
|
||||
login(user, user)
|
||||
then:
|
||||
username == user
|
||||
}
|
||||
|
||||
def 'following links keeps new session'() {
|
||||
when:
|
||||
navLink.click(LinkPage)
|
||||
then:
|
||||
username == 'luke'
|
||||
}
|
||||
|
||||
def 'switch account rob'() {
|
||||
setup:
|
||||
def user = 'rob'
|
||||
when:
|
||||
switchAccount(user)
|
||||
then:
|
||||
username == user
|
||||
}
|
||||
|
||||
def 'following links keeps original session'() {
|
||||
when:
|
||||
navLink.click(LinkPage)
|
||||
then:
|
||||
username == 'rob'
|
||||
}
|
||||
|
||||
def 'switch account luke'() {
|
||||
setup:
|
||||
def user = 'luke'
|
||||
when:
|
||||
switchAccount(user)
|
||||
then:
|
||||
username == user
|
||||
}
|
||||
|
||||
def 'logout luke'() {
|
||||
when:
|
||||
logout.click(HomePage)
|
||||
then:
|
||||
!username
|
||||
}
|
||||
|
||||
def 'switch back rob'() {
|
||||
setup:
|
||||
def user = 'rob'
|
||||
when:
|
||||
switchAccount(user)
|
||||
then:
|
||||
username == user
|
||||
}
|
||||
|
||||
def 'logout rob'() {
|
||||
when:
|
||||
logout.click(HomePage)
|
||||
then:
|
||||
!username
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package sample.pages
|
||||
|
||||
import geb.*
|
||||
|
||||
/**
|
||||
* The home page
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class HomePage extends Page {
|
||||
static url = ''
|
||||
static at = { assert driver.title == 'Demonstrates Multi User Log In'; true}
|
||||
static content = {
|
||||
navLink { $('#navLink') }
|
||||
form { $('form') }
|
||||
username(required:false) { $('#un').text() }
|
||||
logout(required:false) { $('#logout') }
|
||||
addAccount(required:false) { $('#addAccount') }
|
||||
submit { $('input[type=submit]') }
|
||||
login(required:false) { user, pass ->
|
||||
form.username = user
|
||||
form.password = pass
|
||||
submit.click(HomePage)
|
||||
}
|
||||
switchAccount{ un ->
|
||||
$("#switchAccount${un}").click(HomePage)
|
||||
}
|
||||
attributes { moduleList AttributeRow, $("table tr").tail() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package sample.pages
|
||||
|
||||
import geb.*
|
||||
|
||||
/**
|
||||
* The Links Page
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class LinkPage extends Page {
|
||||
static url = ''
|
||||
static at = { assert driver.title == 'Linked Page'; true}
|
||||
static content = {
|
||||
form { $('#navLinks') }
|
||||
username(required:false) { $('#un').text() }
|
||||
switchAccount{ un ->
|
||||
$("#switchAccount${un}").click(HomePage)
|
||||
}
|
||||
}
|
||||
}
|
||||
44
samples/users/src/main/java/sample/Account.java
Normal file
44
samples/users/src/main/java/sample/Account.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample;
|
||||
|
||||
public class Account {
|
||||
private String username;
|
||||
|
||||
private String logoutUrl;
|
||||
|
||||
private String switchAccountUrl;
|
||||
|
||||
public Account(String username, String logoutUrl, String switchAccountUrl) {
|
||||
super();
|
||||
this.username = username;
|
||||
this.logoutUrl = logoutUrl;
|
||||
this.switchAccountUrl = switchAccountUrl;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getLogoutUrl() {
|
||||
return logoutUrl;
|
||||
}
|
||||
|
||||
public String getSwitchAccountUrl() {
|
||||
return switchAccountUrl;
|
||||
}
|
||||
|
||||
}
|
||||
36
samples/users/src/main/java/sample/Config.java
Normal file
36
samples/users/src/main/java/sample/Config.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package sample;
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@Import(EmbeddedRedisConfiguration.class)
|
||||
@Configuration
|
||||
@EnableRedisHttpSession
|
||||
public class Config {
|
||||
|
||||
@Bean
|
||||
public JedisConnectionFactory connectionFactory() {
|
||||
return new JedisConnectionFactory();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package sample;
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import redis.clients.jedis.Protocol;
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
/**
|
||||
* Runs an embedded Redis instance. This is only necessary since we do not want
|
||||
* users to have to setup a Redis instance. In a production environment, this
|
||||
* would not be used since a Redis Server would be setup.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@Configuration
|
||||
public class EmbeddedRedisConfiguration {
|
||||
|
||||
@Bean
|
||||
public RedisServerBean redisServer() {
|
||||
return new RedisServerBean();
|
||||
}
|
||||
|
||||
class RedisServerBean implements InitializingBean, DisposableBean {
|
||||
private RedisServer redisServer;
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
redisServer = new RedisServer(Protocol.DEFAULT_PORT);
|
||||
redisServer.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if(redisServer != null) {
|
||||
redisServer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
samples/users/src/main/java/sample/Initializer.java
Normal file
36
samples/users/src/main/java/sample/Initializer.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package sample;
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class Initializer extends AbstractHttpSessionApplicationInitializer {
|
||||
|
||||
public Initializer() {
|
||||
super(Config.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterSessionRepositoryFilter(ServletContext servletContext) {
|
||||
appendFilters(servletContext, new UserAccountsFilter());
|
||||
}
|
||||
}
|
||||
43
samples/users/src/main/java/sample/LoginServlet.java
Normal file
43
samples/users/src/main/java/sample/LoginServlet.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@WebServlet("/login")
|
||||
public class LoginServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
String username = req.getParameter("username");
|
||||
String password = req.getParameter("password");
|
||||
|
||||
if(username != null && username.equals(password)) {
|
||||
req.getSession().setAttribute("username", username);
|
||||
String url = resp.encodeRedirectURL(req.getContextPath() + "/");
|
||||
resp.sendRedirect(url);
|
||||
}
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -8157634860354132501L;
|
||||
}
|
||||
42
samples/users/src/main/java/sample/LogoutServlet.java
Normal file
42
samples/users/src/main/java/sample/LogoutServlet.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@WebServlet("/logout")
|
||||
public class LogoutServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
HttpSession session = req.getSession(false);
|
||||
if(session != null) {
|
||||
session.invalidate();
|
||||
}
|
||||
String url = resp.encodeRedirectURL(req.getContextPath() + "/");
|
||||
resp.sendRedirect(url);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 4061762524521437433L;
|
||||
}
|
||||
95
samples/users/src/main/java/sample/UserAccountsFilter.java
Normal file
95
samples/users/src/main/java/sample/UserAccountsFilter.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.web.http.HttpSessionManager;
|
||||
|
||||
public class UserAccountsFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
|
||||
HttpSessionManager sessionManager =
|
||||
(HttpSessionManager) req.getAttribute(HttpSessionManager.class.getName());
|
||||
SessionRepository<Session> repo =
|
||||
(SessionRepository<Session>) req.getAttribute(SessionRepository.class.getName());
|
||||
|
||||
String currentSessionAlias = sessionManager.getCurrentSessionAlias(req);
|
||||
Map<String, String> sessionIds = sessionManager.getSessionIds(req);
|
||||
String newSessionAlias = String.valueOf(System.currentTimeMillis());
|
||||
|
||||
String contextPath = req.getContextPath();
|
||||
List<Account> accounts = new ArrayList<>();
|
||||
Account currentAccount = null;
|
||||
for(Map.Entry<String, String> entry : sessionIds.entrySet()) {
|
||||
String alias = entry.getKey();
|
||||
String sessionId = entry.getValue();
|
||||
|
||||
Session session = repo.getSession(sessionId);
|
||||
if(session == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String username = (String) session.getAttribute("username");
|
||||
if(username == null) {
|
||||
newSessionAlias = alias;
|
||||
continue;
|
||||
}
|
||||
|
||||
String logoutUrl = sessionManager.encodeURL("./logout", alias);
|
||||
String switchAccountUrl = sessionManager.encodeURL("./", alias);
|
||||
Account account = new Account(username, logoutUrl, switchAccountUrl);
|
||||
if(currentSessionAlias.equals(alias)) {
|
||||
currentAccount = account;
|
||||
} else {
|
||||
accounts.add(account);
|
||||
}
|
||||
}
|
||||
|
||||
req.setAttribute("currentAccount", currentAccount);
|
||||
req.setAttribute("addAccountUrl", sessionManager.encodeURL(contextPath, newSessionAlias));
|
||||
req.setAttribute("accounts", accounts);
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
}
|
||||
0
samples/users/src/main/webapp/META-INF/MANIFEST.MF
Normal file
0
samples/users/src/main/webapp/META-INF/MANIFEST.MF
Normal file
5
samples/users/src/main/webapp/assets/bootstrap.min.css
vendored
Normal file
5
samples/users/src/main/webapp/assets/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
samples/users/src/main/webapp/assets/js/bootstrap.min.js
vendored
Normal file
7
samples/users/src/main/webapp/assets/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
|
||||
/*!
|
||||
* IE10 viewport hack for Surface/desktop Windows 8 bug
|
||||
* Copyright 2014 Twitter, Inc.
|
||||
* Licensed under the Creative Commons Attribution 3.0 Unported License. For
|
||||
* details, see http://creativecommons.org/licenses/by/3.0/.
|
||||
*/
|
||||
|
||||
// See the Getting Started docs for more information:
|
||||
// http://getbootstrap.com/getting-started/#support-ie10-width
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
|
||||
var msViewportStyle = document.createElement('style')
|
||||
msViewportStyle.appendChild(
|
||||
document.createTextNode(
|
||||
'@-ms-viewport{width:auto!important}'
|
||||
)
|
||||
)
|
||||
document.querySelector('head').appendChild(msViewportStyle)
|
||||
}
|
||||
})();
|
||||
4
samples/users/src/main/webapp/assets/js/jquery.min.js
vendored
Normal file
4
samples/users/src/main/webapp/assets/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
97
samples/users/src/main/webapp/index.jsp
Normal file
97
samples/users/src/main/webapp/index.jsp
Normal file
@@ -0,0 +1,97 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Demonstrates Multi User Log In</title>
|
||||
<link rel="stylesheet" href="assets/bootstrap.min.css">
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- Static navbar -->
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="https://github.com/spring-projects/spring-session/">Spring Session</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<c:url value="/" var="homeUrl"/>
|
||||
<li class="active"><a id="navHome" href="${homeUrl}">Home</a></li>
|
||||
<c:url value="/link.jsp" var="linkUrl"/>
|
||||
<li><a id="navLink" href="${linkUrl}">Link</a></li>
|
||||
|
||||
</ul>
|
||||
<c:if test="${currentAccount != null or not empty accounts}">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><c:out value="${username}"/> <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<c:if test="${currentAccount != null}">
|
||||
<li><a id="logout" href="${currentAccount.logoutUrl}">Log Out</a></li>
|
||||
<li><a id="addAccount" href="${addAccountUrl}">Add Account</a></li>
|
||||
</c:if>
|
||||
<c:if test="${not empty accounts}">
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header">Switch Account</li>
|
||||
<li class="divider"></li>
|
||||
</c:if>
|
||||
<c:forEach items="${accounts}" var="account">
|
||||
<li><a id="switchAccount${account.username}" href="${account.switchAccountUrl}"><c:out value="${account.username}"/></a></li>
|
||||
</c:forEach>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</c:if>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div><!--/.container-fluid -->
|
||||
</nav>
|
||||
|
||||
<h1>Description</h1>
|
||||
<p>This application demonstrates how to use Spring Session to authenticate as multiple users at a time. View authenticated users in the upper right corner.</p>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${username == null}">
|
||||
<h1>Please Log In</h1>
|
||||
<p>You are not currently authenticated with this session. You can authenticate with any username password combination that are equal. A few examples to try:</p>
|
||||
<ul>
|
||||
<li><b>Username</b> rob and <b>Password</b> rob</li>
|
||||
<li><b>Username</b> luke and <b>Password</b> luke</li>
|
||||
</ul>
|
||||
<c:url value="/login" var="loginUrl"/>
|
||||
<form action="${loginUrl}" method="post">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input id="username" type="text" name="username"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input id="password" type="text" name="password"/>
|
||||
</div>
|
||||
<input type="submit" value="Login"/>
|
||||
</form>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<h1 id="un"><c:out value="${username}"/></h1>
|
||||
<p>You are authenticated as <b><c:out value="${username}"/></b>. Observe that you can <a href="${linkUrl}">navigate links</a> and the correct session is used. Using the links in the upper right corner you can:</p>
|
||||
<ul>
|
||||
<li>Log Out</li>
|
||||
<li>Switch Accounts</li>
|
||||
<li>Add Account</li>
|
||||
</ul>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
<!-- Bootstrap core JavaScript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="./assets/js/jquery.min.js"></script>
|
||||
<script src="./assets/js/bootstrap.min.js"></script>
|
||||
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
|
||||
<script src="./assets/js/ie10-viewport-bug-workaround.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
81
samples/users/src/main/webapp/link.jsp
Normal file
81
samples/users/src/main/webapp/link.jsp
Normal file
@@ -0,0 +1,81 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Linked Page</title>
|
||||
<link rel="stylesheet" href="assets/bootstrap.min.css">
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- Static navbar -->
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="https://github.com/spring-projects/spring-session/">Spring Session</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<c:url value="/" var="homeUrl"/>
|
||||
<li><a id="navHome" href="${homeUrl}">Home</a></li>
|
||||
<c:url value="/link.jsp" var="linkUrl"/>
|
||||
<li class="active"><a id="navLink" href="${linkUrl}">Link</a></li>
|
||||
|
||||
</ul>
|
||||
<c:if test="${currentAccount != null or not empty accounts}">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><c:out value="${username}"/> <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<c:if test="${currentAccount != null}">
|
||||
<li><a id="logout" href="${currentAccount.logoutUrl}">Log Out</a></li>
|
||||
<li><a id="addAccount" href="${addAccountUrl}">Add Account</a></li>
|
||||
</c:if>
|
||||
<c:if test="${not empty accounts}">
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header">Switch Account</li>
|
||||
<li class="divider"></li>
|
||||
</c:if>
|
||||
<c:forEach items="${accounts}" var="account">
|
||||
<li><a id="switchAccount${account.username}" href="${account.switchAccountUrl}"><c:out value="${account.username}"/></a></li>
|
||||
</c:forEach>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</c:if>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div><!--/.container-fluid -->
|
||||
</nav>
|
||||
|
||||
<h1>Description</h1>
|
||||
<p>This page demonstrates how we keep track of the correct user session between links even when multiple tabs are open. Try opening another tab with a different user and browse. Then come back to the original tab and see the correct user is maintained.</p>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${username == null}">
|
||||
<h1>Please Log In</h1>
|
||||
<p>You are not currently authenticated with this session. <a href="${homeUrl}">Log In</a></p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<h1 id="un"><c:out value="${username}"/></h1>
|
||||
<p>You are authenticated as <b><c:out value="${username}"/></b>. Observe that you can <a href="${linkUrl}">navigate links</a> and the correct session is used. Using the links in the upper right corner you can:</p>
|
||||
<ul>
|
||||
<li>Log Out</li>
|
||||
<li>Switch Accounts</li>
|
||||
<li>Add Account</li>
|
||||
</ul>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
<!-- Bootstrap core JavaScript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="./assets/js/jquery.min.js"></script>
|
||||
<script src="./assets/js/bootstrap.min.js"></script>
|
||||
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
|
||||
<script src="./assets/js/ie10-viewport-bug-workaround.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user