How session works with redis?

Instead of Tomcat’s Embedded  `HttpSession `stored in memory, *Spring-Session* reimplements `HttpSesson` with Redis to support multiple sessions with same browser.

#### Try it up with debugger

Let's first create a demo project, go to [starter](https://start.spring.io/) page and create a demo project with following plugin:
* Redis
* Web
* Session

Add `@EnableRedisHttpSession` to BootApplication 

```diff
@SpringBootApplication
+ @EnableRedisHttpSession
public class DemoApplication {
	...
}
```

And create a Hello Controller for [debugging](https://www.jetbrains.com/help/idea/debugging-code.html)

```java
@RestController
@RequestMapping("/")
public class Hello {

  @GetMapping("hello")
  public String hello(HttpServletRequest request, @RequestParam String value){
    // add debugger here
    request.getSession().setAttribute("key",value);
    return value;
  }
}
```

 Add debugger with `find usage` for getter/setter

```java
org.springframework.session.web.http.SessionRepositoryFilter#CURRENT_SESSION_ATTR
```

Cookies resolver

```
org.springframework.session.web.http.CookieHttpSessionIdResolver#resolveSessionIds
```

And these are the mapping between cookies and redis

```
org.springframework.session.web.http.DefaultCookieSerializer#readCookieValues
org.springframework.session.web.http.DefaultCookieSerializer#writeCookieValue
```

then start a local redis(localhost:6379) and run springboot in debug mode.

Let's try with a curl

```sh
 curl "http://localhost:8080/hello?value=1"
```

Finally, login to redis-cli, you will find sessions are already in Redis.

```
KEYS spring:session:sessions:*
```



#### How to reuse session-id?

By default, session ids are generated by UUID, they have no relation with browser or IP address.

```
org.springframework.session.MapSession#generateId
```

To reuse the session-id, every request from browser must have a valid seesion in the header(cookies or x-auth-token), I prefer header based session resolver (less payload and easier for non-browser  clients).

```java
@Bean
HttpSessionIdResolver headerResolver(){
	return new HeaderHttpSessionIdResolver("miao-token");
}
```

Recurl and your will get a `miao-token` header in response.

```properties
Content-Type: ...
Date: ...
miao-token: f15b28ea-15b6-4ce8-aad5-9ed0ab00d643
```

To keep the client's session up to date with server, just add the header in HttpInterceptor(eg: okhttp/ajax).

```js
// angular HttpInterceptor, same as okhttp
export class AddHeaderInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const clonedRequest = req.clone({ 
    	headers: req.headers.set('miao-token', YOUR_GLOBAL_TOKEN) 
		});
    return next.handle(clonedRequest);
  }
}
```

In the end, here is the resuable process flow.

```
RESTful Request
	|
HttpSessionIdResolver
	|
(has token id)?
	|  
	|-------(yes): get seesion by id from redis and reuse.
	---------(no): jump to login page and create id by UUID
```



## Appendix

#### What's cookie's scope?

See [Scope of cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Scope_of_cookies), if you share two war with same session, you need to customize the `DefaultCookieSerializer`  for wider scope.

#### CSRF protection

*CSRF(Cross-Site Request Forgery)* attacks may  inject malicious code into webpages, see more at [Spring-Securiy](https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/csrf.html) for server-side protection and [Angular](https://angular.io/guide/security) for client-side protection.

#### Alternatives

If you prefer a *lower* level redis store implementation, just try [tomcat-redis-session-manager](<https://github.com/jcoleman/tomcat-redis-session-manager>)

```
com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve
```