Web登录功能及其安全验证

发布时间 2023-12-16 22:31:36作者: 奕帆卷卷

登录认证

业务分析

系统的登录认证,本质上是查询语句,查询数据库中用户名与密码是否与前端传来的相同。

列如前端来数据为

{
	"username": "jinyong",
    "password": "123456"
}

在controller层进行接收,并调用Service层的方法处理后响应结果

在Service层调用Mapper层方法查询username和password

在Mapper层进行sql语句查询

业务实现

controller

    /**
     * 登录
     *
     */
    @PostMapping("/login")
public Result login(@RequestBody Emp emp) {
log.info("登录成功");
LoginIfo loginIfo= empService.login(emp);

if (loginIfo!=null){
return Result.success(loginIfo);
}
    return Result.error("用户名或者密码错误!");
    }

Service

 @Override
    public LoginIfo login(Emp emp) {
        Emp e = empMapper.getByUsernameAndPassword(emp);


        //判断
        if (e!=null){//登录成功,生成JWT令牌
            Map<String,Object> claims=new HashMap<>();
            claims.put("id",e.getId());
            claims.put("username",e.getUsername());
            claims.put("name",e.getName());

            String jwt = JwtUtils.generateJwt(claims);

            LoginIfo loginIfo = new LoginIfo(e.getId(),e.getUsername(),e.getName(),jwt);
            return loginIfo;
        }
        return null;
    }

Mapper

@Select("select * from emp where username=#{username} and password=#{password}")
    Emp getByUsernameAndPassword(Emp emp);

登录校验

在完成登录功能之后,登录成功后就可以进入到后台管理系统中进行系统数据的操作,但是如果直接输入网址后,也能进行数据操作,我们需要对用户是否登录的状态进行判断,如果没有登录,则跳转登录页面进行登录。

所谓 登录校验,就是服务器端对浏览器的每次请求,都要进行一次检验用户是否登录,如果用户没有登录,不允许请求的业务操作,返回前端响应一个错误结果,并跳转到登录页面

问题分析

由于HTTP协议是无状态的,每次http协议请求之间都是独立的,当http在之前实现了登录操作,后面发送请求时,服务器无法判断是否登录

实现思路

  1. 在员工登录成功之后,需要将用户登录成功的信息存起来,记录用户已经登录成功的标记
  2. 在浏览器发起请求的时候,需要在服务器进行统一拦截,拦截之后进行登录校验

为了代码的简洁性,我们可以通过统一拦截的方式,列如过滤器或者拦截器等

因为在系统中的功能都需要进行登录校验,相同的代码逻辑,通过统一拦截技术,我们拦截浏览器发送的请求,拦截请求后,通过请求来获取之前发送的登录标记,如果可以获取到,则说明员工已经登录成功,我们之间放行,没有获取到登录标记,返回错误,注意在登录功能不需要获取登录标记

会话技术

我们在Web开发中,我们将浏览器和服务器之间的一次连接,我们就称为一次会话

在浏览器发起请求的时候,这个会话就建立了,一直到有任何一方断开连接,会话结束,一次会话可以有多次请求和响应。

会话跟踪

  • 会话跟踪:

    一种维护浏览器状态的方法,服务器需要识别多次请求是否是来自同一个浏览器,以便在同一个会话中多次请求共享数据

会话跟踪技术常见有三种:

  1. Cookie(客户端会话跟踪技术)
    • 数据存储在客户端浏览器中
  2. Session(服务端会话跟踪技术)
    • 数据存储在服务端
  3. 令牌技术

方案一:Cookie

方案介绍

cookie是客户端会话跟踪技术,它是存储在客户端浏览器的,我们在浏览器第一次发起请求时,我们在服务器端设置一个cookie,我们在cookie中我们可以来存储用户的一些数据信息,在第一次服务器端在给客户端响应数据的时候(登录),会自动的将cookie响应给浏览器本地,接下来的每次浏览器请求,都会将浏览器本地储存的cookie携带到请求中,服务器来判断请求中是否存在cookie是否存在,如果不存在这个cookie,就说明客户端没有进行登录操作,禁止进行操作,如果存在,则说明已经进行登录完成。

由于cookie是HTTP协议中支持的技术,所以服务器和浏览器可以自动携带,并且提供了一个响应头和请求头用来携带cookie

  • 响应头 Set-Cookie:设置Cookie数据
  • 请求头 Cookie:携带Cookie数据

代码测试

@Slf4j
@RestController
public class SessionController {

    //设置Cookie
    @GetMapping("/c1")
    public Result cookie1(HttpServletResponse response){
        response.addCookie(new Cookie("login_username","itheima")); //设置Cookie/响应Cookie
        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()); //输出name为login_username的cookie
            }
        }
        return Result.success();
    }
}    
优点

HTTP协议中支持的技术,浏览器和服务器携带的cookie都是自动进行,无需手动操作

缺点
  • 移动端App无法使用
  • 不安全,浏览器可以禁用Cookie
  • Cookie不能跨域

方案二:Session

方案介绍

服务器端会话跟踪技术,因为他是存储在服务器端的

浏览器在第一次请求服务器的时候,我们可以在服务器中来获取会话对象Session,如果是第一次请求Session,由于会话对象是不存在的,这个时候服务器会自动的创建一个会话对象Session。接下来服务器端再给浏览器每次响应数据的时候,它会将Session的ID通过Cookie响应给浏览器,其实在响应头当中增加了一个Set-Cookie,cookie的名字是固定的服务器端会话对象id,浏览器会自动识别这个响应头,然后自动的将cookie存储在浏览器本地

后续的每次请求当中,都会将Cookie的数据获取出来,并且携带到服务端,然后根据cookie的数据跟众多的Sesion中来找到当前请求对应的会话对象Session

代码

@Slf4j
@RestController
public class SessionController {

    //设置Cookie
    @GetMapping("/c1")
    public Result cookie1(HttpServletResponse response){
        response.addCookie(new Cookie("login_username","itheima")); //设置Cookie/响应Cookie
        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()); //输出name为login_username的cookie
            }
        }
        return Result.success();
    }
}    
优点

Session是存储在服务端的,安全

缺点
  • 服务器集群环境下无法直接使用Session
  • 移动端APP(Android、IOS)中无法使用Cookie
  • 用户可以自己禁用Cookie
  • Cookie不能跨域

方案三:令牌技术

方案介绍

其实它就是一个用户身份的标识,本质上是一个字符串。

在登陆成功后,我们生成一个令牌,令牌作为用户的合法凭证,接下来在响应数据的时候,我们就可以直接将令牌响应给前端。

后续的每一次请求,都会将令牌携带给服务端,携带到服务器端后,检验令牌是否有效,如果有效则说明用户已经完成登录操作,否则反之

如果我们在同一次会话的多次请求,想要共享数据,我们就可以将共享的数据存储在令牌当中

优点
  • 支持PC端、移动端
  • 解决集群环境下的认证问题
缺点

要自己实现(包括令牌的生成、令牌的传递、令牌的校验)