目录
简单登录实现(有问题)
先捋一遍,为了后面更好的学习。
Controller层
@RestController
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
log.info("员工登录:{}",emp);
Emp e = empService.login(emp);
return e != null ? Result.success():Result.error("用户名或密码错误");
Service层
@Override
public Emp login(Emp emp){
Emp e=empMapper.getByUsernameAndPassword(emp);
return e;
Mapper层
//根据用户名及密码查询员工信息
@Select("select * from emp where username = #{username} and password = #{password}")
Emp getByUsernameAndPassword(Emp emp);
测试
问题
在未登录情况下,我们也可以直接访问部门管理、员工管理等功能。
会话技术
1.会话
用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
2.会话跟踪
一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
3.会话跟踪方案
客户端会话跟踪技术:cookie
服务端会话跟踪技术:session
cookie
1.定义
cookie 是一种键值对数据,通常由服务器在 HTTP 响应头中通过 Set-Cookie
指令发送给客户端浏览器,浏览器会将其存储起来,并在随后的请求中自动发送回服务器。
cookie就是一些数据,用于存储服务器返回给客服端的信息,客户端进行保存。在下一次访问该网站时,客户端会将保存的cookie一同发给服务器,服务器再利用cookie进行一些操作。利用cookie我们就可以实现自动登录,保存游览历史,身份验证等功能。
2.演示请求响应过程
@Slf4j
@RestController
public class SessionController {
//设置cookie
@GetMapping("/c1")
public Result cookie1(HttpServletResponse response){
response.addCookie(new Cookie("login_username","mikey"));//key/value
return Result.success();
}
//获取cookie
@GetMapping("/c2")
public Result cookie2(HttpServletRequest request){
Cookie[] cookies = request.getCookies();
for(Cookie cookie : cookies){
if(cookie.getName().equals("login_username")){
System.out.println("login_username:"+cookie.getValue());
}
}
return Result.success();
}
}
浏览器先访问:localhost:8080/c1
浏览器向客户端发送c1请求 响应头中的set-cookie就是我们在服务器端所响应回来的cookie 浏览器拿到这个响应回来的数据之后 会自动地解析响应头 如果看到有一个响应头叫set-cookie 浏览器会自动地将这个cookie的值存储在浏览器本地
具体存储在
1.Value
:Cookie的值。
2.Expires
:Cookie的过期时间。
3.Max-Age
:Cookie的生命周期,以秒为单位。
4.Domain
:Cookie有效的域名。
5.Path
:Cookie有效的路径。这个定义了Web站点上可以访问该Cookie的目录
6.Secure
:指示Cookie只能通过HTTPS发送。
7.HttpOnly
:指示Cookie不能被JavaScript访问,增加了安全性。
浏览器再访问:localhost:8080/c2
发现当访问c2这个接口时,请求把cookie携带到了服务端,而且是在请求头cookie中携带到服务端的。
执行完c2后,控制台也输出了cookie键值对。
所以,只要是当前这个浏览器所发起的请求,来请求当前8080端口这个服务端,每一次请求都会将这个cookie值携带过来,这样就可以在多次请求之间共享数据啦!
总结
cookie在进行会话跟踪时,最为核心的就是一个请求头一个响应头,响应头set-cookie用来设置cookie数据;请求头cookie用来携带cookie数据。
不能跨域:如果前端和后端部署在不同的域名或端口上,发送请求的url会变,cookie没办法带过去,Cookie不会随跨域请求发送。
session
1.定义
Session在网络应用中称为“会话控制”,是服务器为了保存用户状态而创建的一个特殊的对象。简而言之,Session就是一个对象,用于存储信息。
2.session有什么用?
我们先来想一个问题,这个问题就是我们在游览购物网站时,我们并没有登录,但是我们任然可以将商品加入购物车,并且进行查看,当我们退出游览器后再打开游览器进行查看时,购物车中依然有我们选择的商品,这该怎么实现呢?
当然,我们可以使用cookie,但是cookie能存放大量数据吗?这时,我们就需要一种新的技术,session。session是存储于服务器端的特殊对象,服务器会为每一个游览器(客户端)创建一个唯一的session。这个Session是服务器端共享,每个游览器(客户端)独享的。我们可以在session存储数据,实现数据共享。
3.演示请求响应过程
获取到会话对象session,HttpSession就是会话对象session,此时服务器端会判断当前这一次请求对应的会话对象session到底存不存在,如果不存在,创建一个新的session;如果存在,服务器就会获取到当前这一次请求对应的session。
s1请求过后,就会往session这个会话对象中来存储loginuser这个值。
//往session中存储数据
@GetMapping("/s1")
public Result session1(HttpSession session){
log.info("HttpSession-s1: {}", session.hashCode());
session.setAttribute("loginUser", "77"); //往session中存储数据
return Result.success();
}
JSESSIONID后的一长串代表的是服务器端session会话对象的id值,浏览器接收到这个cookie之后,就将cookie值存储起来了。
s2请求通过第二种方式来获取会话对象,声明了个request对象,通过request.getSession(),就可以拿到当前这次请求对应的会话对象,也可以获取到httpSession这个会话对象。
@GetMapping("/s2")
public Result session2(HttpServletRequest request){
HttpSession session = request.getSession();
log.info("HttpSession-s2: {}", session.hashCode());
Object loginUser = session.getAttribute("loginUser"); //从session中获取数据
log.info("loginUser: {}", loginUser);
return Result.success(loginUser);
}
s2请求中,请求头中将两个cookie都携带了服务端,服务器端接收到了这个session的id之后,服务器会根据这个id找到找到这次请求对应的session会话对象。
控制台输出的两次请求拿到的会话对象session是同一个,日志输出的hashcode都一样。s1存,s2取。底层也是cookie。
服务器集群环境下无法直接使用session:现在开发的项目不止部署在一台服务器,用户访问时会先访问负载均衡服务器,它的作用时将前端发起的请求均匀的发给后面的n台服务器,假如说我们通过session来进行会话跟踪,负载均衡服务器会传给哪服务器是未知的,可能发送两次请求之后获取的也是两个不能的会话对象。
现在的主流解决方案时JWT令牌技术。