由于本篇讲解的是初步的拦截和验证,所以比较简单,不涉及角色权限等,以下是我后面讲解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,实现退出登录功能!