Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f8403659e | ||
|
|
8cc3fd14e1 | ||
|
|
6b29fef71a | ||
|
|
c51aa38087 | ||
|
|
ff02a3b7be | ||
|
|
d02f0279a3 | ||
|
|
3bb26735b7 | ||
|
|
2fa4aecd13 | ||
|
|
8645271d0b | ||
|
|
00ac080069 | ||
|
|
e0309c0519 | ||
|
|
5f27de9d28 | ||
|
|
9de05feb9f | ||
|
|
fe32f7a66b | ||
|
|
1b63952e58 | ||
|
|
94009301d5 | ||
|
|
ada7a35458 | ||
|
|
19d4d1d521 | ||
|
|
025b6e99dd | ||
|
|
dd6f5ac7a8 | ||
|
|
69c1e3f6b2 | ||
|
|
9c77691232 | ||
|
|
8a1f5253ce | ||
|
|
c44954ea5c | ||
|
|
441fc363a1 | ||
|
|
fcf3f4a542 | ||
|
|
78684c7ef8 | ||
|
|
6d2ffb173b | ||
|
|
35acf0b537 | ||
|
|
d6482f36de | ||
|
|
9992d32dc1 | ||
|
|
3c912ec87b | ||
|
|
a8e8bc5db1 | ||
|
|
d22983bef8 | ||
|
|
1746ad630b | ||
|
|
953db5c611 | ||
|
|
fb0b2691d2 | ||
|
|
2bdc416621 | ||
|
|
bbec4bd8e6 | ||
|
|
dba5ad7412 | ||
|
|
f4038dc5c7 | ||
|
|
12dc76ec36 | ||
|
|
7be3d30981 | ||
|
|
9c8fe23789 | ||
|
|
3114ef51ec | ||
|
|
9e7736bf7f | ||
|
|
6c5e335568 | ||
|
|
1deedad3b9 | ||
|
|
e4a8a6aa5c | ||
|
|
49375a28fa | ||
|
|
5375f51bca | ||
|
|
29af9d3a4d | ||
|
|
997ff56c63 | ||
|
|
06d8031211 | ||
|
|
904369ac29 | ||
|
|
266854a0be | ||
|
|
8f02c83e06 | ||
|
|
570a7686b1 | ||
|
|
fed318abc7 | ||
|
|
a824edd1c3 | ||
|
|
aa4f783b45 | ||
|
|
11fb68444f | ||
|
|
00026a30f4 | ||
|
|
c007437bd3 | ||
|
|
dda13b5619 | ||
|
|
366f13bd25 | ||
|
|
3535137c47 | ||
|
|
a9bca9088f | ||
|
|
31de86ecef | ||
|
|
d123960f89 | ||
|
|
16d2923efd | ||
|
|
24015d0854 | ||
|
|
d8f160c178 | ||
|
|
0318f6e2c1 | ||
|
|
43dd571345 | ||
|
|
e7fb9fce47 | ||
|
|
f13eb8d73e | ||
|
|
1a07ba5114 | ||
|
|
7125aac567 |
7
.github/ISSUE_TEMPLATE.md
vendored
7
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,7 +0,0 @@
|
||||
<!--
|
||||
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
|
||||
-->
|
||||
|
||||
<!--
|
||||
Thanks for raising a Spring Session issue. Please provide a brief description of your problem along with the version of Spring Session that you are using. If possible, please also consider putting together a sample application that reproduces the issue.
|
||||
-->
|
||||
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: 'type: bug, status: waiting-for-triage'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Sample**
|
||||
|
||||
A link to a GitHub repository with a [minimal, reproducible sample](https://stackoverflow.com/help/minimal-reproducible-example).
|
||||
|
||||
Reports that include a sample will take priority over reports that do not.
|
||||
At times, we may require a sample, so it is good to try and include a sample up front.
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Community Support
|
||||
url: https://stackoverflow.com/questions/tagged/spring-security
|
||||
about: Please ask and answer questions on StackOverflow with the tag spring-session
|
||||
25
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: 'status: waiting-for-triage, type: enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Expected Behavior**
|
||||
|
||||
<!--- Tell us how it should work -->
|
||||
|
||||
**Current Behavior**
|
||||
|
||||
<!--- Explain the difference from current behavior -->
|
||||
|
||||
**Context**
|
||||
|
||||
<!---
|
||||
How has this issue affected you?
|
||||
What are you trying to accomplish?
|
||||
What other alternatives have you considered?
|
||||
Are you aware of any workarounds?
|
||||
-->
|
||||
28
.github/workflows/pr-build-workflow.yml
vendored
Normal file
28
.github/workflows/pr-build-workflow.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: 2.3.x PR Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- 2.3.x
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
jdk: [8, 11]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK ${{ matrix.jdk }}
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
- name: Cache Gradle packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew clean build --no-daemon --stacktrace
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,3 +13,4 @@ out
|
||||
.checkstyle
|
||||
!etc/eclipse/.checkstyle
|
||||
!**/src/**/build
|
||||
.DS_Store
|
||||
|
||||
16
.travis.yml
16
.travis.yml
@@ -1,16 +0,0 @@
|
||||
sudo: required
|
||||
language: java
|
||||
jdk:
|
||||
- openjdk8
|
||||
- openjdk11
|
||||
services:
|
||||
- docker
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
install: true
|
||||
script: ./gradlew clean check --no-daemon --stacktrace
|
||||
@@ -1,44 +0,0 @@
|
||||
= Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering an open
|
||||
and welcoming community, we pledge to respect all people who contribute through reporting
|
||||
issues, posting feature requests, updating documentation, submitting pull requests or
|
||||
patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for
|
||||
everyone, regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
|
||||
religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses,
|
||||
without explicit permission
|
||||
* Other unethical or unprofessional conduct
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments,
|
||||
commits, code, wiki edits, issues, and other contributions that are not aligned to this
|
||||
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
|
||||
that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
|
||||
consistently applying these principles to every aspect of managing this project. Project
|
||||
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
|
||||
from the project team.
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an
|
||||
individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
|
||||
contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will
|
||||
be reviewed and investigated and will result in a response that is deemed necessary and
|
||||
appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
|
||||
with regard to the reporter of an incident.
|
||||
|
||||
This Code of Conduct is adapted from the
|
||||
https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
|
||||
https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
|
||||
@@ -3,9 +3,16 @@
|
||||
Spring Session is released under the Apache 2.0 license. If you would like to contribute
|
||||
something, or simply want to hack on the code this document should help you get started.
|
||||
|
||||
|
||||
== Code of Conduct
|
||||
This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct].
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
||||
|
||||
Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct]
|
||||
|
||||
|
||||
== Reporting Security Vulnerabilities
|
||||
|
||||
Please see our https://github.com/spring-projects/spring-session/security/policy[Security policy].
|
||||
|
||||
|
||||
== Using GitHub issues
|
||||
|
||||
|
||||
181
Jenkinsfile
vendored
181
Jenkinsfile
vendored
@@ -1,181 +0,0 @@
|
||||
properties([
|
||||
buildDiscarder(logRotator(numToKeepStr: '10')),
|
||||
pipelineTriggers([
|
||||
cron('@daily')
|
||||
]),
|
||||
])
|
||||
|
||||
def SUCCESS = hudson.model.Result.SUCCESS.toString()
|
||||
currentBuild.result = SUCCESS
|
||||
|
||||
try {
|
||||
parallel check: {
|
||||
stage('Check') {
|
||||
timeout(time: 45, unit: 'MINUTES') {
|
||||
node('linux') {
|
||||
label 'spring-session'
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk8'}"]) {
|
||||
sh './gradlew clean check --no-daemon --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: check'
|
||||
throw e
|
||||
}
|
||||
finally {
|
||||
junit '**/build/test-results/*/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
jdk9: {
|
||||
stage('JDK 9') {
|
||||
timeout(time: 45, unit: 'MINUTES') {
|
||||
node('linux') {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk9'}"]) {
|
||||
sh './gradlew clean test --no-daemon --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: jdk9'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
jdk10: {
|
||||
stage('JDK 10') {
|
||||
timeout(time: 45, unit: 'MINUTES') {
|
||||
node('linux') {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk10'}"]) {
|
||||
sh './gradlew clean test --no-daemon --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: jdk10'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
jdk11: {
|
||||
stage('JDK 11') {
|
||||
timeout(time: 45, unit: 'MINUTES') {
|
||||
node('linux') {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk11'}"]) {
|
||||
sh './gradlew clean test integrationTest --no-daemon --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: jdk11'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
jdk12: {
|
||||
stage('JDK 12') {
|
||||
timeout(time: 45, unit: 'MINUTES') {
|
||||
node('linux') {
|
||||
checkout scm
|
||||
try {
|
||||
withEnv(["JAVA_HOME=${tool 'openjdk12'}"]) {
|
||||
sh './gradlew clean test integrationTest --no-daemon --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: jdk12'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentBuild.result == 'SUCCESS') {
|
||||
parallel artifacts: {
|
||||
stage('Deploy Artifacts') {
|
||||
node('linux') {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withCredentials([file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')]) {
|
||||
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
|
||||
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
|
||||
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk8'}"]) {
|
||||
sh './gradlew deployArtifacts --no-daemon --stacktrace -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password=$SIGNING_PASSWORD -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD'
|
||||
sh './gradlew finalizeDeployArtifacts --no-daemon --stacktrace -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password=$SIGNING_PASSWORD -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: artifacts'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
docs: {
|
||||
stage('Deploy Docs') {
|
||||
node('linux') {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk8'}"]) {
|
||||
sh './gradlew deployDocs --no-daemon --stacktrace -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME'
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: docs'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
def buildStatus = currentBuild.result
|
||||
def buildNotSuccess = !SUCCESS.equals(buildStatus)
|
||||
def lastBuildNotSuccess = !SUCCESS.equals(currentBuild.previousBuild?.result)
|
||||
|
||||
if (buildNotSuccess || lastBuildNotSuccess) {
|
||||
stage('Notify') {
|
||||
node {
|
||||
final def RECIPIENTS = [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']]
|
||||
|
||||
def subject = "${buildStatus}: Build ${env.JOB_NAME} ${env.BUILD_NUMBER} status is now ${buildStatus}"
|
||||
def details = "The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}"
|
||||
|
||||
emailext(
|
||||
subject: subject,
|
||||
body: details,
|
||||
recipientProviders: RECIPIENTS,
|
||||
to: "$SPRING_SESSION_TEAM_EMAILS"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
README.adoc
20
README.adoc
@@ -1,6 +1,14 @@
|
||||
[NOTE]
|
||||
======
|
||||
This branch of Spring Session has reached its https://github.com/spring-projects/spring-boot/wiki/Supported-Versions[End of Life], meaning that there are no further maintenance releases or security patches planned.
|
||||
Please migrate to a supported branch as soon as possible.
|
||||
======
|
||||
|
||||
= Spring Session
|
||||
|
||||
image:https://travis-ci.org/spring-projects/spring-session.svg?branch=master["Build Status", link="https://travis-ci.org/spring-projects/spring-session"] image:https://badges.gitter.im/spring-projects/spring-session.svg[link="https://gitter.im/spring-projects/spring-session?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
|
||||
image:https://badges.gitter.im/spring-projects/spring-session.svg[link="https://gitter.im/spring-projects/spring-session?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
|
||||
|
||||
image:https://github.com/spring-projects/spring-session/workflows/CI/badge.svg?branch=master["Build Status", link="https://github.com/spring-projects/spring-session/actions?query=workflow%3ACI"]
|
||||
|
||||
Spring Session provides an API and implementations for managing a user's session information, while also making it trivial to support clustered sessions without being tied to an application container specific solution.
|
||||
It also provides transparent integration with:
|
||||
@@ -18,10 +26,16 @@ Spring Session consists of the following modules:
|
||||
* Spring Session JDBC - provides `SessionRepository` implementation backed by a relational database and configuration support
|
||||
* Spring Session Hazelcast - provides `SessionRepository` implementation backed by Hazelcast and configuration support
|
||||
|
||||
|
||||
== Code of Conduct
|
||||
|
||||
This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct].
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
||||
Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct]
|
||||
|
||||
|
||||
== Reporting Security Vulnerabilities
|
||||
|
||||
Please see our https://github.com/spring-projects/spring-session/security/policy[Security policy].
|
||||
|
||||
|
||||
== Spring Session Project Site
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ buildscript {
|
||||
snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
milestoneBuild = !(releaseBuild || snapshotBuild)
|
||||
|
||||
springBootVersion = '2.2.4.RELEASE'
|
||||
springBootVersion = '2.2.13.RELEASE'
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -13,7 +13,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'io.spring.gradle:spring-build-conventions:0.0.27.RELEASE'
|
||||
classpath 'io.spring.gradle:spring-build-conventions:0.0.37'
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
org.gradle.parallel=true
|
||||
version=2.3.0.M1
|
||||
version=2.3.4.BUILD-SNAPSHOT
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'io.projectreactor:reactor-bom:Dysprosium-SR4'
|
||||
mavenBom 'org.junit:junit-bom:5.5.2'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.2.3.RELEASE'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Neumann-M2'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.3.0.M1'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.12.2'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Dysprosium-SR19'
|
||||
mavenBom 'org.junit:junit-bom:5.6.3'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.2.14.RELEASE'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Neumann-SR8'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.3.9.RELEASE'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.15.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.12.5') {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.12.12') {
|
||||
entry 'hazelcast'
|
||||
entry 'hazelcast-client'
|
||||
}
|
||||
|
||||
dependency 'com.h2database:h2:1.4.199'
|
||||
dependency 'com.h2database:h2:1.4.200'
|
||||
dependency 'com.ibm.db2:jcc:11.5.0.0'
|
||||
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.4.1.jre8'
|
||||
dependency 'com.oracle.ojdbc:ojdbc8:19.3.0.0'
|
||||
dependency 'com.zaxxer:HikariCP:3.4.1'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'io.lettuce:lettuce-core:5.2.0.RELEASE'
|
||||
dependency 'io.lettuce:lettuce-core:5.2.2.RELEASE'
|
||||
dependency 'javax.annotation:javax.annotation-api:1.3.2'
|
||||
dependency 'javax.servlet:javax.servlet-api:4.0.1'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'mysql:mysql-connector-java:8.0.17'
|
||||
dependency 'junit:junit:4.13'
|
||||
dependency 'mysql:mysql-connector-java:8.0.21'
|
||||
dependency 'org.apache.derby:derby:10.14.2.0'
|
||||
dependency 'org.assertj:assertj-core:3.13.2'
|
||||
dependency 'org.hsqldb:hsqldb:2.5.0'
|
||||
dependency 'org.assertj:assertj-core:3.15.0'
|
||||
dependency 'org.hsqldb:hsqldb:2.5.1'
|
||||
dependency 'org.mariadb.jdbc:mariadb-java-client:2.4.4'
|
||||
dependency 'org.mockito:mockito-core:3.0.0'
|
||||
dependency 'org.postgresql:postgresql:42.2.8'
|
||||
dependency 'org.mockito:mockito-core:3.3.3'
|
||||
dependency 'org.postgresql:postgresql:42.2.16'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ import org.springframework.session.events.SessionDestroyedEvent;
|
||||
*
|
||||
* {@literal @Bean}
|
||||
* public MapSessionRepository sessionRepository() {
|
||||
* return new MapSessionRepository();
|
||||
* return new MapSessionRepository(new ConcurrentHashMap<>());
|
||||
* }
|
||||
*
|
||||
* }
|
||||
|
||||
@@ -58,7 +58,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*
|
||||
* {@literal @Bean}
|
||||
* public MapSessionRepository sessionRepository() {
|
||||
* return new MapSessionRepository();
|
||||
* return new MapSessionRepository(new ConcurrentHashMap<>());
|
||||
* }
|
||||
*
|
||||
* }
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.context.annotation.Import;
|
||||
*
|
||||
* {@literal @Bean}
|
||||
* public ReactiveSessionRepository sessionRepository() {
|
||||
* return new ReactiveMapSessionRepository();
|
||||
* return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
|
||||
* }
|
||||
*
|
||||
* }
|
||||
|
||||
@@ -308,7 +308,7 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
/**
|
||||
* Sets the maxAge property of the Cookie. The default is to delete the cookie when
|
||||
* the browser is closed.
|
||||
* @param cookieMaxAge the maxAge property of the Cookie
|
||||
* @param cookieMaxAge the maxAge property of the Cookie (defined in seconds)
|
||||
*/
|
||||
public void setCookieMaxAge(int cookieMaxAge) {
|
||||
this.cookieMaxAge = cookieMaxAge;
|
||||
|
||||
@@ -309,6 +309,10 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
if (!create) {
|
||||
return null;
|
||||
}
|
||||
if (SessionRepositoryFilter.this.httpSessionIdResolver instanceof CookieHttpSessionIdResolver
|
||||
&& this.response.isCommitted()) {
|
||||
throw new IllegalStateException("Cannot create a session after the response has been committed");
|
||||
}
|
||||
if (SESSION_LOGGER.isDebugEnabled()) {
|
||||
SESSION_LOGGER.debug(
|
||||
"A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for "
|
||||
|
||||
@@ -62,6 +62,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
@@ -423,6 +424,18 @@ class SessionRepositoryFilterTests {
|
||||
assertThat(this.response.getCookie("SESSION")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterGetSessionNewWhenResponseCommittedThenException() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest, HttpServletResponse wrappedResponse)
|
||||
throws IOException {
|
||||
wrappedResponse.getWriter().flush();
|
||||
wrappedRequest.getSession();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilterGetSessionNew() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
*/
|
||||
public abstract class AbstractRedisITests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
protected static class BaseConfig {
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ import org.springframework.util.Assert;
|
||||
* <p>
|
||||
* When a session is created an event is sent to Redis with the channel of
|
||||
* "spring:session:channel:created:33fdd1b6-b496-4b33-9f7d-df96679d32fe" such that
|
||||
* "33fdd1b6-b496-4b33-9f7d-df96679d32fe" is the sesion id. The body of the event will be
|
||||
* "33fdd1b6-b496-4b33-9f7d-df96679d32fe" is the session id. The body of the event will be
|
||||
* the session that was created.
|
||||
* </p>
|
||||
*
|
||||
|
||||
@@ -25,7 +25,22 @@ dependencies {
|
||||
|
||||
def versions = dependencyManagement.managedVersions
|
||||
|
||||
asciidoctorPdf {
|
||||
clearSources()
|
||||
sources {
|
||||
include "index.adoc"
|
||||
}
|
||||
}
|
||||
|
||||
asciidoctor {
|
||||
clearSources()
|
||||
sources {
|
||||
include "index.adoc"
|
||||
include "guides/*.adoc"
|
||||
}
|
||||
}
|
||||
|
||||
asciidoctorj {
|
||||
def ghTag = snapshotBuild ? 'master' : project.version
|
||||
def ghUrl = "https://github.com/spring-projects/spring-session/tree/$ghTag"
|
||||
|
||||
@@ -46,5 +61,7 @@ asciidoctor {
|
||||
'spring-session-version': project.version,
|
||||
'version-milestone': milestoneBuild,
|
||||
'version-release': releaseBuild,
|
||||
'version-snapshot': snapshotBuild
|
||||
'version-snapshot': snapshotBuild,
|
||||
'highlightjsdir@': "js/highlight",
|
||||
'docinfodir@': "."
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
= Spring Session - find by username
|
||||
Rob Winch
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to find sessions by username.
|
||||
|
||||
NOTE: You can find the completed guide in the <<findbyusername-sample, findbyusername application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
[[findbyusername-assumptions]]
|
||||
== Assumptions
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
= Spring Session - Spring Boot
|
||||
Rob Winch, Vedran Pavić
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` when you use Spring Boot.
|
||||
|
||||
NOTE: You can find the completed guide in the <<httpsession-jdbc-boot-sample, httpsession-jdbc-boot sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
|
||||
Before you use Spring Session, you must update your dependencies.
|
||||
@@ -46,6 +52,9 @@ spring.session.store-type=jdbc # Session store type.
|
||||
----
|
||||
====
|
||||
|
||||
If a single Spring Session module is present on the classpath, Spring Boot uses that store implementation automatically.
|
||||
If you have more than one implementation, you must choose the StoreType that you wish to use to store the sessions, as shows above.
|
||||
|
||||
Under the hood, Spring Boot applies configuration that is equivalent to manually adding the `@EnableJdbcHttpSession` annotation.
|
||||
This creates a Spring bean with the name of `springSessionRepositoryFilter`. That bean implements `Filter`.
|
||||
The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
= Spring Session - Spring Boot
|
||||
Rob Winch, Vedran Pavić
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when you use Spring Boot.
|
||||
|
||||
NOTE: You can find the completed guide in the <<boot-sample, boot sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
|
||||
Before you use Spring Session, you must ensure your dependencies.
|
||||
@@ -53,7 +59,7 @@ Further customization is possible by using `application.properties`, as the foll
|
||||
.src/main/resources/application.properties
|
||||
----
|
||||
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds is used.
|
||||
spring.session.redis.flush-mode=on-save # Sessions flush mode.
|
||||
spring.session.redis.flush-mode=on_save # Sessions flush mode.
|
||||
spring.session.redis.namespace=spring:session # Namespace for keys used to store sessions.
|
||||
----
|
||||
====
|
||||
@@ -151,6 +157,6 @@ To do so, enter the following into your terminal, being sure to replace `7e8383a
|
||||
----
|
||||
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
|
||||
----
|
||||
=====
|
||||
====
|
||||
|
||||
Now you can visit the application at http://localhost:8080/ and observe that we are no longer authenticated.
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
= Spring Session - WebFlux with Custom Cookie
|
||||
Eleftheria Stein-Kousathana
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to configure Spring Session to use custom cookies in a WebFlux based application.
|
||||
The guide assumes you have already set up Spring Session in your project using your chosen data store. For example, link:./boot-redis.html[HttpSession with Redis].
|
||||
|
||||
NOTE: You can find the completed guide in the <<webflux-custom-cookie-sample, WebFlux Custom Cookie sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
[[webflux-custom-cookie-spring-configuration]]
|
||||
== Spring Boot Configuration
|
||||
|
||||
Once you have set up Spring Session, you can customize how the session cookie is written by exposing a `WebSessionIdResolver` as a Spring bean.
|
||||
Spring Session uses a `CookieWebSessionIdResolver` by default.
|
||||
Exposing the `WebSessionIdResolver` as a Spring bean augments the existing configuration when you use configurations like `@EnableRedisHttpSession`.
|
||||
The following example shows how to customize Spring Session's cookie:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{samples-dir}spring-session-sample-boot-webflux-custom-cookie/src/main/java/sample/CookieConfig.java[tags=webflux-cookie-serializer]
|
||||
----
|
||||
|
||||
<1> We customize the name of the cookie to be `JSESSIONID`.
|
||||
<2> We customize the path of the cookie to be `/` (rather than the default of the context root).
|
||||
<3> We customize the `SameSite` cookie directive to be `Strict`.
|
||||
====
|
||||
|
||||
[[webflux-custom-cookie-sample]]
|
||||
== `webflux-custom-cookie` Sample Application
|
||||
|
||||
This section describes how to work with the `webflux-custom-cookie` sample application.
|
||||
|
||||
=== Running the `webflux-custom-cookie` Sample Application
|
||||
|
||||
You can run the sample by obtaining the {download-url}[source code] and invoking the following command:
|
||||
|
||||
====
|
||||
----
|
||||
$ ./gradlew :spring-session-sample-boot-webflux-custom-cookie:bootRun
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
|
||||
Alternatively, you can update the `RedisConnectionFactory` to point to a Redis server.
|
||||
Another option is to use https://www.docker.com/[Docker] to run Redis on localhost. See https://hub.docker.com/_/redis/[Docker Redis repository] for detailed instructions.
|
||||
|
||||
You should now be able to access the application at http://localhost:8080/
|
||||
|
||||
=== Exploring the `webflux-custom-cookie` Sample Application
|
||||
|
||||
Now you can use the application. Fill out the form with the following information:
|
||||
|
||||
* *Attribute Name:* _username_
|
||||
* *Attribute Value:* _rob_
|
||||
|
||||
Now click the *Set Attribute* button.
|
||||
You should now see the values displayed in the table.
|
||||
|
||||
If you look at the cookies for the application, you can see the cookie is saved to the custom name of `JSESSIONID`.
|
||||
@@ -1,7 +1,10 @@
|
||||
= Spring Session - WebSocket
|
||||
Rob Winch
|
||||
:toc:
|
||||
:toc: left
|
||||
:websocketdoc-test-dir: {docs-test-dir}docs/websocket/
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to ensure that WebSocket messages keep your HttpSession alive.
|
||||
|
||||
@@ -12,9 +15,12 @@ Specifically,it does not work with using https://www.jcp.org/en/jsr/detail?id=35
|
||||
|
||||
// end::disclaimer[]
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== HttpSession Setup
|
||||
|
||||
The first step is to integrate Spring Session with the HttpSession. These steps are already outlined in the link:httpsession.html[HttpSession Guide].
|
||||
The first step is to integrate Spring Session with the HttpSession. These steps are already outlined in the link:./boot-redis.html[HttpSession with Redis Guide].
|
||||
|
||||
Please make sure you have already integrated Spring Session with HttpSession before proceeding.
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<script type="text/javascript" src="../js/tocbot/tocbot.min.js"></script>
|
||||
<script type="text/javascript" src="../js/toc.js"></script>
|
||||
@@ -1,12 +1,18 @@
|
||||
= Spring Session - Custom Cookie
|
||||
Rob Winch; Eleftheria Stein-Kousathana
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to configure Spring Session to use custom cookies with Java Configuration.
|
||||
The guide assumes you have already link:./httpsession.html[set up Spring Session in your project].
|
||||
The guide assumes you have already set up Spring Session in your project using your chosen data store. For example, link:./boot-redis.html[HttpSession with Redis].
|
||||
|
||||
NOTE: You can find the completed guide in the <<custom-cookie-sample, Custom Cookie sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
[[custom-cookie-spring-configuration]]
|
||||
== Spring Java Configuration
|
||||
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
= Spring Session and Spring Security with Hazelcast
|
||||
Tommy Ludwig; Rob Winch
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session along with Spring Security when you use Hazelcast as your data store.
|
||||
It assumes that you have already applied Spring Security to your application.
|
||||
|
||||
NOTE: You cand find the completed guide in the <<hazelcast-spring-security-sample, Hazelcast Spring Security sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
|
||||
Before you use Spring Session, you must update your dependencies.
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
= Spring Session - HttpSession (Quick Start)
|
||||
Rob Winch, Vedran Pavić
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` with Java Configuration.
|
||||
|
||||
NOTE: You can find the completed guide in the <<httpsession-jdbc-sample, httpsession-jdbc sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
|
||||
Before you use Spring Session, you must update your dependencies.
|
||||
@@ -99,7 +105,7 @@ For additional information on how to configure data access related concerns, see
|
||||
|
||||
== Java Servlet Container Initialization
|
||||
|
||||
Our <<httpsession-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
|
||||
Our <<httpsession-jdbc-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
|
||||
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
|
||||
|
||||
In order for our `Filter` to do its magic, Spring needs to load our `Config` class.
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
= Spring Session - HttpSession (Quick Start)
|
||||
Rob Winch
|
||||
:toc:
|
||||
:toc: left
|
||||
:version-snapshot: true
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with Java Configuration.
|
||||
|
||||
NOTE: You can find the completed guide in the <<httpsession-sample, httpsession sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
Before you use Spring Session, you must update your dependencies.
|
||||
If you are using Maven, you must add the following dependencies:
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
= Spring Session - REST
|
||||
Rob Winch
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when you use REST endpoints.
|
||||
|
||||
NOTE: You can find the completed guide in the <<rest-sample, rest sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
|
||||
Before you use Spring Session, you must update your dependencies.
|
||||
@@ -241,7 +247,7 @@ $ curl -v http://localhost:8080/ -u user:password
|
||||
|
||||
In the output, you should notice the following:
|
||||
|
||||
===
|
||||
====
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
...
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
= Spring Session and Spring Security
|
||||
Rob Winch
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session along with Spring Security.
|
||||
It assumes you have already applied Spring Security to your application.
|
||||
|
||||
NOTE: You can find the completed guide in the <<security-sample, security sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
Before you use Spring Session, you must update your dependencies.
|
||||
If you use Maven, you must add the following dependencies:
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
= Spring Session - HttpSession (Quick Start)
|
||||
Rob Winch, Vedran Pavić
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to transparently leverage a relational to back a web application's `HttpSession` with XML based configuration.
|
||||
|
||||
NOTE: You can find the completed guide in the <<httpsession-jdbc-xml-sample, httpsession-jdbc-xml sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
|
||||
Before you use Spring Session, you must update your dependencies.
|
||||
@@ -68,8 +74,8 @@ You must have the following in your pom.xml:
|
||||
<url>https://repo.spring.io/libs-milestone</url>
|
||||
</repository>
|
||||
----
|
||||
endif::[]
|
||||
====
|
||||
endif::[]
|
||||
|
||||
// tag::config[]
|
||||
|
||||
@@ -101,7 +107,7 @@ For additional information on how to configure data access-related concerns, see
|
||||
|
||||
== XML Servlet Container Initialization
|
||||
|
||||
Our <<httpsession-xml-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
|
||||
Our <<httpsession-jdbc-xml-spring-configuration,Spring Configuration>> created a Spring bean named `springSessionRepositoryFilter` that implements `Filter`.
|
||||
The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session.
|
||||
|
||||
In order for our `Filter` to do its magic, we need to instruct Spring to load our `session.xml` configuration.
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
= Spring Session - HttpSession (Quick Start)
|
||||
Rob Winch
|
||||
:toc:
|
||||
:toc: left
|
||||
:stylesdir: ../
|
||||
:highlightjsdir: ../js/highlight
|
||||
:docinfodir: guides
|
||||
|
||||
This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with XML-based configuration.
|
||||
|
||||
NOTE: You can find the completed guide in the <<httpsession-xml-sample, httpsession-xml sample application>>.
|
||||
|
||||
[#index-link]
|
||||
link:../index.html[Index]
|
||||
|
||||
== Updating Dependencies
|
||||
Before you use Spring Session, you must update your dependencies.
|
||||
If you use Maven, you must add the following dependencies:
|
||||
|
||||
@@ -70,6 +70,10 @@ To get started with Spring Session, the best place to start is our Sample Applic
|
||||
| Demonstrates how to use Spring Session to replace the Spring WebFlux's `WebSession` with Redis.
|
||||
|
|
||||
|
||||
| {gh-samples-url}spring-session-sample-boot-webflux-custom-cookie[WebFlux with Custom Cookie]
|
||||
| Demonstrates how to use Spring Session to customize the Session cookie in a WebFlux based application.
|
||||
| link:guides/boot-webflux-custom-cookie.html[WebFlux with Custom Cookie Guide]
|
||||
|
||||
| {gh-samples-url}spring-session-sample-boot-redis-json[HttpSession with Redis JSON serialization]
|
||||
| Demonstrates how to use Spring Session to replace the `HttpSession` with Redis using JSON serialization.
|
||||
|
|
||||
@@ -289,7 +293,7 @@ Any method that returns an `HttpSession` is overridden.
|
||||
All other methods are implemented by `HttpServletRequestWrapper` and delegate to the original `HttpServletRequest` implementation.
|
||||
|
||||
We replace the `HttpServletRequest` implementation by using a servlet `Filter` called `SessionRepositoryFilter`.
|
||||
The pseudocode belows:
|
||||
The following pseudocode shows how it works:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
|
||||
@@ -19,6 +19,7 @@ package docs.security;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
@@ -41,14 +42,16 @@ public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapte
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// ... additional configuration ...
|
||||
.rememberMe()
|
||||
.rememberMeServices(rememberMeServices());
|
||||
.rememberMe((rememberMe) -> rememberMe
|
||||
.rememberMeServices(rememberMeServices())
|
||||
);
|
||||
// end::http-rememberme[]
|
||||
|
||||
http
|
||||
.formLogin().and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated();
|
||||
.formLogin(Customizer.withDefaults())
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
}
|
||||
|
||||
// tag::rememberme-bean[]
|
||||
|
||||
@@ -40,9 +40,10 @@ public class SecurityConfiguration<S extends Session> extends WebSecurityConfigu
|
||||
// @formatter:off
|
||||
http
|
||||
// other config goes here...
|
||||
.sessionManagement()
|
||||
.sessionManagement((sessionManagement) -> sessionManagement
|
||||
.maximumSessions(2)
|
||||
.sessionRegistry(sessionRegistry());
|
||||
.sessionRegistry(sessionRegistry())
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
||||
@WebAppConfiguration
|
||||
class ClientServerHazelcastIndexedSessionRepositoryITests extends AbstractHazelcastIndexedSessionRepositoryITests {
|
||||
|
||||
private static GenericContainer container = new GenericContainer<>("hazelcast/hazelcast:3.12.3")
|
||||
private static GenericContainer container = new GenericContainer<>("hazelcast/hazelcast:3.12.12")
|
||||
.withExposedPorts(5701).withCopyFileToContainer(MountableFile.forClasspathResource("/hazelcast-server.xml"),
|
||||
"/opt/hazelcast/hazelcast.xml");
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ import org.springframework.util.StringUtils;
|
||||
* );
|
||||
*
|
||||
* CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
|
||||
* CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (EXPIRY_TIME);
|
||||
* CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
|
||||
* CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
*
|
||||
* CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.10.0'
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.10.5.20201202'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -9,15 +9,15 @@ dependencyManagement {
|
||||
dependency 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2'
|
||||
dependency 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.3'
|
||||
dependency 'org.apache.taglibs:taglibs-standard-jstlel:1.2.5'
|
||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.33.0'
|
||||
dependency 'org.slf4j:jcl-over-slf4j:1.7.28'
|
||||
dependency 'org.slf4j:log4j-over-slf4j:1.7.28'
|
||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.33.3'
|
||||
dependency 'org.slf4j:jcl-over-slf4j:1.7.30'
|
||||
dependency 'org.slf4j:log4j-over-slf4j:1.7.30'
|
||||
dependency 'org.webjars:bootstrap:2.3.2'
|
||||
dependency 'org.webjars:html5shiv:3.7.3'
|
||||
dependency 'org.webjars:jquery:1.12.4'
|
||||
dependency 'org.webjars:knockout:2.3.0'
|
||||
dependency 'org.webjars:sockjs-client:0.3.4'
|
||||
dependency 'org.webjars:stomp-websocket:2.3.0'
|
||||
dependency 'org.webjars:stomp-websocket:2.3.4'
|
||||
dependency 'org.webjars:webjars-taglib:0.3'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,13 +46,15 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
|
||||
class FindByUsernameTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
private WebDriver driver2;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build();
|
||||
@@ -61,6 +63,9 @@ class FindByUsernameTests {
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
this.driver.quit();
|
||||
if (this.driver2 != null) {
|
||||
this.driver2.quit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,6 +84,25 @@ class FindByUsernameTests {
|
||||
home.terminateButtonDisabled();
|
||||
}
|
||||
|
||||
@Test
|
||||
void terminateOtherSession() throws Exception {
|
||||
HomePage forgotToLogout = home(this.driver);
|
||||
|
||||
this.driver2 = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build();
|
||||
HomePage terminateFogotSession = home(this.driver2);
|
||||
terminateFogotSession.terminateSession(forgotToLogout.getSessionId()).assertAt();
|
||||
|
||||
LoginPage login = HomePage.go(this.driver);
|
||||
login.assertAt();
|
||||
}
|
||||
|
||||
private static HomePage home(WebDriver driver) {
|
||||
LoginPage login = HomePage.go(driver);
|
||||
HomePage home = login.form().login(HomePage.class);
|
||||
home.assertAt();
|
||||
return home;
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
static class Config {
|
||||
|
||||
|
||||
@@ -56,6 +56,18 @@ public class HomePage extends BasePage {
|
||||
}
|
||||
|
||||
public void terminateButtonDisabled() {
|
||||
String sessionId = getSessionId();
|
||||
WebElement element = getDriver().findElement(By.id("terminate-" + sessionId));
|
||||
assertThat(element.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
public HomePage terminateSession(String sessionId) {
|
||||
WebElement terminate = getDriver().findElement(By.id("terminate-" + sessionId));
|
||||
terminate.click();
|
||||
return new HomePage(getDriver());
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
Set<Cookie> cookies = getDriver().manage().getCookies();
|
||||
String cookieValue = null;
|
||||
for (Cookie cookie : cookies) {
|
||||
@@ -63,8 +75,7 @@ public class HomePage extends BasePage {
|
||||
cookieValue = new String(Base64.getDecoder().decode(cookie.getValue()));
|
||||
}
|
||||
}
|
||||
WebElement element = getDriver().findElement(By.id("terminate-" + cookieValue));
|
||||
assertThat(element.isEnabled()).isFalse();
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
public HomePage logout() {
|
||||
|
||||
@@ -35,13 +35,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
)
|
||||
.formLogin((formLogin) -> formLogin
|
||||
.loginPage("/login")
|
||||
.permitAll();
|
||||
.permitAll()
|
||||
);
|
||||
}
|
||||
// end::config[]
|
||||
// @formatter:on
|
||||
|
||||
@@ -26,8 +26,8 @@ import org.springframework.session.Session;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Controller for sending the user to the login view.
|
||||
@@ -50,7 +50,7 @@ public class IndexController {
|
||||
}
|
||||
// end::findbyusername[]
|
||||
|
||||
@RequestMapping(value = "/sessions/{sessionIdToDelete}", method = RequestMethod.DELETE)
|
||||
@PostMapping("/sessions/{sessionIdToDelete}")
|
||||
public String removeSession(Principal principal, @PathVariable String sessionIdToDelete) {
|
||||
Set<String> usersSessionIds = this.sessions.findByPrincipalName(principal.getName()).keySet();
|
||||
if (usersSessionIds.contains(sessionIdToDelete)) {
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<td th:text="${#temporals.format(sessionElement.lastAccessedTime.atZone(T(java.time.ZoneId).systemDefault()),'dd/MMM/yyyy HH:mm:ss')}"></td>
|
||||
<td th:text="${details?.accessType}"></td>
|
||||
<td>
|
||||
<form th:action="@{'/sessions/' + ${sessionElement.id}}" th:method="delete">
|
||||
<form th:action="@{'/sessions/' + ${sessionElement.id}}" th:method="post">
|
||||
<input th:id="'terminate-' + ${sessionElement.id}" type="submit" value="Terminate" th:disabled="${sessionElement.id == #httpSession.id}"/>
|
||||
</form>
|
||||
</td>
|
||||
|
||||
@@ -44,12 +44,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll();
|
||||
)
|
||||
.formLogin((formLogin) -> formLogin
|
||||
.permitAll()
|
||||
);
|
||||
}
|
||||
// end::config[]
|
||||
// @formatter:on
|
||||
|
||||
@@ -50,7 +50,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@AutoConfigureMockMvc
|
||||
class HttpRedisJsonTest {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@SpringBootTest
|
||||
class RedisSerializerTest {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@SpringSessionRedisOperations
|
||||
private RedisTemplate<Object, Object> sessionRedisTemplate;
|
||||
|
||||
@@ -34,13 +34,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
)
|
||||
.formLogin((formLogin) -> formLogin
|
||||
.loginPage("/login")
|
||||
.permitAll();
|
||||
.permitAll()
|
||||
);
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
|
||||
class BootTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -28,12 +28,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll();
|
||||
)
|
||||
.formLogin((formLogin) -> formLogin
|
||||
.permitAll()
|
||||
);
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
|
||||
class BootTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -35,12 +35,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll();
|
||||
)
|
||||
.formLogin((formLogin) -> formLogin
|
||||
.permitAll()
|
||||
);
|
||||
}
|
||||
// end::config[]
|
||||
// @formatter:on
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework.boot:spring-boot-starter-webflux"
|
||||
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
|
||||
compile "org.springframework.boot:spring-boot-starter-data-redis"
|
||||
compile "org.springframework.boot:spring-boot-devtools"
|
||||
compile 'org.webjars:bootstrap'
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
testCompile "org.junit.jupiter:junit-jupiter-api"
|
||||
testRuntime "org.junit.jupiter:junit-jupiter-engine"
|
||||
|
||||
integrationTestCompile seleniumDependencies
|
||||
integrationTestCompile "org.testcontainers:testcontainers"
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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
|
||||
*
|
||||
* https://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.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import sample.pages.HomePage;
|
||||
import sample.pages.HomePage.Attribute;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
class AttributeTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.driver = new HtmlUnitDriver();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
this.driver.quit();
|
||||
}
|
||||
|
||||
@Test
|
||||
void home() {
|
||||
HomePage home = HomePage.go(this.driver, this.port);
|
||||
home.assertAt();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noAttributes() {
|
||||
HomePage home = HomePage.go(this.driver, this.port);
|
||||
assertThat(home.attributes()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAttribute() {
|
||||
HomePage home = HomePage.go(this.driver, this.port);
|
||||
// @formatter:off
|
||||
home = home.form()
|
||||
.attributeName("a")
|
||||
.attributeValue("b")
|
||||
.submit(HomePage.class);
|
||||
// @formatter:on
|
||||
|
||||
List<Attribute> attributes = home.attributes();
|
||||
assertThat(attributes).hasSize(1);
|
||||
Attribute row = attributes.get(0);
|
||||
assertThat(row.getAttributeName()).isEqualTo("a");
|
||||
assertThat(row.getAttributeValue()).isEqualTo("b");
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
GenericContainer redisContainer() {
|
||||
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE).withExposedPorts(6379);
|
||||
redisContainer.start();
|
||||
return redisContainer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
LettuceConnectionFactory redisConnectionFactory() {
|
||||
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
|
||||
redisContainer().getFirstMappedPort());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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
|
||||
*
|
||||
* https://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.pages;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.openqa.selenium.SearchContext;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.PageFactory;
|
||||
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
public class HomePage {
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
@FindBy(css = "form")
|
||||
WebElement form;
|
||||
|
||||
@FindBy(css = "table tbody tr")
|
||||
List<WebElement> trs;
|
||||
|
||||
List<Attribute> attributes;
|
||||
|
||||
public HomePage(WebDriver driver) {
|
||||
this.driver = driver;
|
||||
this.attributes = new ArrayList<>();
|
||||
}
|
||||
|
||||
private static void get(WebDriver driver, int port, String get) {
|
||||
String baseUrl = "http://localhost:" + port;
|
||||
driver.get(baseUrl + get);
|
||||
}
|
||||
|
||||
public static HomePage go(WebDriver driver, int port) {
|
||||
get(driver, port, "/");
|
||||
return PageFactory.initElements(driver, HomePage.class);
|
||||
}
|
||||
|
||||
public void assertAt() {
|
||||
assertThat(this.driver.getTitle()).isEqualTo("Session Attributes");
|
||||
}
|
||||
|
||||
public List<Attribute> attributes() {
|
||||
List<Attribute> rows = new ArrayList<>();
|
||||
for (WebElement tr : this.trs) {
|
||||
rows.add(new Attribute(tr));
|
||||
}
|
||||
this.attributes.addAll(rows);
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public Form form() {
|
||||
return new Form(this.form);
|
||||
}
|
||||
|
||||
public class Form {
|
||||
|
||||
@FindBy(name = "attributeName")
|
||||
WebElement attributeName;
|
||||
|
||||
@FindBy(name = "attributeValue")
|
||||
WebElement attributeValue;
|
||||
|
||||
@FindBy(css = "input[type=\"submit\"]")
|
||||
WebElement submit;
|
||||
|
||||
public Form(SearchContext context) {
|
||||
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
|
||||
}
|
||||
|
||||
public Form attributeName(String text) {
|
||||
this.attributeName.sendKeys(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Form attributeValue(String text) {
|
||||
this.attributeValue.sendKeys(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> T submit(Class<T> page) {
|
||||
this.submit.click();
|
||||
return PageFactory.initElements(HomePage.this.driver, page);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Attribute {
|
||||
|
||||
@FindBy(xpath = ".//td[1]")
|
||||
WebElement attributeName;
|
||||
|
||||
@FindBy(xpath = ".//td[2]")
|
||||
WebElement attributeValue;
|
||||
|
||||
public Attribute(SearchContext context) {
|
||||
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the attributeName
|
||||
*/
|
||||
public String getAttributeName() {
|
||||
return this.attributeName.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the attributeValue
|
||||
*/
|
||||
public String getAttributeValue() {
|
||||
return this.attributeValue.getText();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ryuk.container.timeout=120
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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
|
||||
*
|
||||
* https://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 org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.server.session.CookieWebSessionIdResolver;
|
||||
import org.springframework.web.server.session.WebSessionIdResolver;
|
||||
|
||||
/**
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
@Configuration
|
||||
public class CookieConfig {
|
||||
|
||||
// tag::webflux-cookie-serializer[]
|
||||
@Bean
|
||||
public WebSessionIdResolver webSessionIdResolver() {
|
||||
CookieWebSessionIdResolver resolver = new CookieWebSessionIdResolver();
|
||||
resolver.setCookieName("JSESSIONID"); // <1>
|
||||
resolver.addCookieInitializer((builder) -> builder.path("/")); // <2>
|
||||
resolver.addCookieInitializer((builder) -> builder.sameSite("Strict")); // <3>
|
||||
return resolver;
|
||||
}
|
||||
// end::webflux-cookie-serializer[]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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
|
||||
*
|
||||
* https://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 org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class HelloWebFluxApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HelloWebFluxApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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
|
||||
*
|
||||
* https://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;
|
||||
|
||||
/**
|
||||
* @author Eleftheria Stein
|
||||
*/
|
||||
public class SessionAttributeForm {
|
||||
|
||||
private String attributeName;
|
||||
|
||||
private String attributeValue;
|
||||
|
||||
public String getAttributeName() {
|
||||
return this.attributeName;
|
||||
}
|
||||
|
||||
public void setAttributeName(String attributeName) {
|
||||
this.attributeName = attributeName;
|
||||
}
|
||||
|
||||
public String getAttributeValue() {
|
||||
return this.attributeValue;
|
||||
}
|
||||
|
||||
public void setAttributeValue(String attributeValue) {
|
||||
this.attributeValue = attributeValue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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
|
||||
*
|
||||
* https://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 org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.server.WebSession;
|
||||
|
||||
// tag::class[]
|
||||
@Controller
|
||||
public class SessionController {
|
||||
|
||||
@PostMapping("/session")
|
||||
public String setAttribute(@ModelAttribute SessionAttributeForm sessionAttributeForm, WebSession session) {
|
||||
session.getAttributes().put(sessionAttributeForm.getAttributeName(), sessionAttributeForm.getAttributeValue());
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String index(Model model, WebSession webSession) {
|
||||
model.addAttribute("webSession", webSession);
|
||||
return "index";
|
||||
}
|
||||
|
||||
}
|
||||
// tag::end[]
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Session Attributes</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Description</h1>
|
||||
<p>This application demonstrates how to customize the session cookie. Notice that the name of the cookie is JSESSIONID.</p>
|
||||
|
||||
<h1>Try it</h1>
|
||||
|
||||
<form class="form-inline" role="form" action="./session" method="post">
|
||||
<label for="attributeName">Attribute Name</label>
|
||||
<input id="attributeName" type="text" name="attributeName"/>
|
||||
<label for="attributeValue">Attribute Value</label>
|
||||
<input id="attributeValue" type="text" name="attributeValue"/>
|
||||
<input type="submit" value="Set Attribute"/>
|
||||
</form>
|
||||
|
||||
<hr/>
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute Name</th>
|
||||
<th>Attribute Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="attr : ${webSession.attributes}">
|
||||
<td th:text="${attr.key}"/></td>
|
||||
<td th:text="${attr.value}"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -47,7 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
class AttributeTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@@ -52,7 +52,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
class ApplicationTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private String port;
|
||||
|
||||
@@ -53,12 +53,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll();
|
||||
)
|
||||
.formLogin((formLogin) -> formLogin
|
||||
.permitAll()
|
||||
);
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -37,4 +37,4 @@ public class SessionServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = 2878267318695777395L;
|
||||
|
||||
}
|
||||
// tag::end[]
|
||||
// end::class[]
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -38,4 +38,4 @@ public class SessionServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = 2878267318695777395L;
|
||||
|
||||
}
|
||||
// tag::end[]
|
||||
// end::class[]
|
||||
|
||||
@@ -53,7 +53,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@WebAppConfiguration
|
||||
class RestMockMvcTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Autowired
|
||||
private SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package sample;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
@@ -31,13 +32,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.authorizeRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.requestCache()
|
||||
)
|
||||
.requestCache((requestCache) -> requestCache
|
||||
.requestCache(new NullRequestCache())
|
||||
.and()
|
||||
.httpBasic();
|
||||
)
|
||||
.httpBasic(Customizer.withDefaults());
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.6";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.10";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
Reference in New Issue
Block a user