SpringBoot进阶(九)登录验证及拦截

929 阅读4分钟

由于本篇讲解的是初步的拦截和验证,所以比较简单,不涉及角色权限等,以下是我后面讲解Shiro安全框架时所需用到的数据库表,你可以提前创建,也可仅创建user表来进行本篇文章的学习!(前几篇我们创建过一个user表,你可以在此基础上修改,或删除重新创建)

GitHub:github.com/baiyuliang/…

在这里插入图片描述

当然,此user表中许多字段是无关紧要的,你可以选择忽略它!

User:

package com.byl.springboottest.bean;

import javax.persistence.*;
import java.io.Serializable;

@Entity(name = "user")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
    private Integer id;
    @Column(unique = true)
    private String username;
    @Column(name = "role_id")
    private Integer roleId;
    @Column
    private String nickname;
    @Column
    private String realname;
    @Column
    private String password;
    @Column
    private String salt;
    @Column
    private Integer gender;
    @Column
    private Integer age;
    @Column
    private Integer status;
    @Column
    private Integer createtime;
    @Column
    private Integer createby;

    ...setter/getter
}

为user表中添加一条数据,保证id,username,password这三个字段不能为空,好来测试登录验证!

在这里插入图片描述

打开dao下的UserRepository,写数据库登录请求方法:

User findByUsernameAndPassword(String username,String password);

注意 findBy后面,都是根据提示自动生成的!

打开UserService:

 User login(String username,String password);

UserServiceImpl实现:

    @Override
    public User login(String username, String password) {
        return null;
    }

到这里时,我们就要思考一下,是不是要稍微正规一点了,我们知道,一个真正的接口,返回的内容,都是有一定格式的,前面也提到过,如:

{
	code:1,
	msg:"请求成功",
	data:{
	
	}
}

真正的数据内容,放在data里,code和msg则表示本次接口请求是否成功的状态,好了,我们现在写一个返回数据的封装类吧:

ResponseData:

package com.byl.springbootdemo.bean.data;

import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;


public class ResponseData implements Serializable {
    private int code;
    private String msg;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Object data;//如果为空,则不返回

    public ResponseData() {

    }

    public ResponseData(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ResponseData(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

@JsonInclude(JsonInclude.Include.NON_NULL)这个注解作用就是,如果该字段是null的情况下,就不会再返回给前端,前端可能受到的信息就只有:{code:1,msg:""}了!

接着,前面也提到过,我们不应该在Controller里再写业务逻辑代码,所以所有的业务都要放在Service中进行,因此ResponseData,我们要封装好后返回给Controller调用,修改UserService以及Impl方法返回值:

 ResponseData login(String username, String password);
 @Override
    public ResponseData login(String username, String password) {
        return null;
    }

继续实现login的具体业务,我们前面已经引入了userRepository:

  @Resource
  UserRepository userRepository;

所以在login方法中直接使用,最终登录业务实现:

    @Override
    public ResponseData login(String username, String password) {
        ResponseData responseData = new ResponseData();
        User user = userRepository.findByUsernameAndPassword(username, password);
        if (user == null) {
            responseData.setCode(-1);
            responseData.setMsg("账号或密码错误");
        } else {
            responseData.setCode(1);
            responseData.setMsg("登录成功");
            responseData.setData(user);
        }
        return responseData;
    }

测试:

    @Test
    void testLogin() {
        ResponseData responseData = userService.login("admin", "admin");
        System.out.println(JSON.toJSON(responseData));
    }

结果: 在这里插入图片描述 没有问题,OK,现在开始写Controller层了:

UserController:

    @PostMapping("/login")
    public ResponseData login(String username, String password) {
        //判断空逻辑省略...
        return userService.login(username, password);
    }

在login.html中写js登录方法:

   // 进行登录操作
   form.on('submit(login)', function (data) {
       data = data.field;
       if (data.username === '') {
           layer.msg('用户名不能为空');
           return false;
       }
       if (data.password === '') {
           layer.msg('密码不能为空');
           return false;
       }
       if (data.captcha === '') {
           layer.msg('验证码不能为空');
           return false;
       }
       $.post("user/login", {
           username: data.username,
           password: data.password
       }, function (data) {
           console.log(data);
          // if (data.code === 1) {
             //     window.location.href = "index";
             // } else {
             //     layer.msg("账号或密码错误,请重新输入!")
             // }
       });
       return false;
   });

注意:

在这里插入图片描述

我先将登录验证成功后的逻辑隐藏,目的是为了打印接口返回结果:

在这里插入图片描述 OK,放开那部分代码,让你来,是不是也成功了呢?!

登录验证成功了,但是此时一个最大也最明显的漏洞就是登不登录好像没有任何作用,即便不登录,我也可以直接通过url访问深层次的页面...,那如何去拦截非登录用户的请求呢?拦截?对,这就用到SpringBoot的拦截器了,新建interceptor文件夹,编写LoginHandlerInterceptor拦截器:

package com.byl.springboottest.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 拦截器
 */
public class LoginHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object username = request.getSession().getAttribute("username");//取出session
        if (username == null) {
            response.sendRedirect(request.getContextPath() + "/login");
            return false;//拦截
        } else {
            return true;//放行
        }
    }

}


利用Session来存储登录用户信息,别慌,还没有完,此时还需要在AppConfig中配置拦截器:

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginHandlerInterceptor())
                .addPathPatterns("/**")//拦截所有
                .excludePathPatterns("/", "/login", "/login.html", "/user/login")//排除
                .excludePathPatterns("/css/**", "/images/**", "/js/**", "/lib/**");//排除
    }

最后修改Controller中的登录方法,存入session:

    @PostMapping("/login")
    public ResponseData login(String username, String password, HttpSession session) {
        //判断空逻辑省略...
        session.setAttribute("username", username);
        return userService.login(username, password);
    }

重新启动项目,你可以再输入除登录界面外的其他url地址,如:http://localhost:8080/byl/index,你会发现,没有登录的情况下,全部都重定向到了登录界面,登录成功后,才可以再去访问其他界面!

当然,你也可以定义一个退出登录接口,来清空session,实现退出登录功能!