cookie+token+拦截器实现自动登录
原理:一般情况下拦截器判断登录状态,是通过获取session中的用户信息来判断的。但session是存储在服务器端的,浏览器一关闭,当前session就失效了。为了实现自动登录(就是一段时间内,比如一个月,每次访问该网址都自动登录上了),我们使用cookie,cookie指明了浏览器信息,处于安全性的考虑,在登录时,我们生成一个随机的token,将这个token和当前登录的用户信息对应,存储在数据库中,并且将该token写进cookie。这样每次浏览器发出请求,只需要检查cookie所带的token是否存在于数据库中,若存在,则取出对应的用户信息给session;若不存在,则重定向到登录。
AdminController
处理登录请求
@PostMapping("/adminLogin")
public String adminLogin(@Param("userName") String userName, @Param("password") String password, HttpServletRequest request, HttpServletResponse response,Model model) {
Admin admin = adminService.adminLogin(userName, password);
if (admin == null) {
model.addAttribute("msg","账号密码错误");
return "index";
}
//存token进数据库
String tokenUUID = UUID.randomUUID().toString();
token.setInfo(userName);
token.setTokenUUID(tokenUUID);
tokenService.addToken(token);
//存token进cookie
Cookie cookie=new Cookie("token",tokenUUID);
//这里需要注意要将cookie路径设置为根目录
cookie.setPath("/");
//设置到期时间为一个月 默认-1关闭浏览器即消失
cookie.setMaxAge(60 * 60 * 24 * 30);
response.addCookie(cookie);
request.getSession().setAttribute("admin", admin);
return "admin/index";
}
LoginInterceptor
拦截器,prehandler方法每次请求前都执行
//登录检查拦截器
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Resource
private ITokenService tokenService;
@Resource
private IAdminService adminService;
@Resource
private IUserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURL=request.getRequestURI();
log.info("preHandle Interceptor路径:"+requestURL);
//自动登录检查业务逻辑
//获取cookie中的token,查询该token在服务器中是否存在,如果存在说明登录过,创建session对话,将对象塞入(不拦截)
Cookie[] cookies=request.getCookies();
if(cookies!=null&&cookies.length!=0) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("token")) {
String token = cookie.getValue();
log.info(token);
tokenService.p();
//查找数据库中是否有该token对象
String username = tokenService.searchToken(token);
if (!username.equals("")) {
//判断这个username是admin还是user
Admin admin = adminService.findAdmin(username);
User user = userService.findUser(username);
if (admin != null)
request.getSession().setAttribute("admin", admin);
if (user != null)
request.getSession().setAttribute("user", user);
log.info("preHandle Interceptor 放行");
}
break;
}
}
}
HttpSession session=request.getSession();
Object admin=session.getAttribute("admin");
Object user=session.getAttribute("user");
if(admin!=null||user!=null){
log.info("preHandle Interceptor 放行");
return true;
}
//拦截,跳转登录页
log.info("preHandle Interceptor 拦截");
request.setAttribute("msg","请先登录");
request.getRequestDispatcher("/").forward(request,response);
return false;
}
}
3.AdminWebConfig
配置拦截器,设定拦截范围
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
// 拦截器的加载如果采用new的方式会导致拦截器自动注入的TokenServiceImpl是null
// 解决:重写的WebMvcConfigurer在添加拦截器之前用@bean注解将拦截器注入工厂,接着添加拦截器
// 就不会出现mapper是null的情况了。
@Bean
public LoginInterceptor interceptor(){
return new LoginInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor())
.addPathPatterns("/**")//所有请求都被拦截,包括静态资源
.excludePathPatterns("/","/error","/adminLogin","/userLogin","/css/**","/images/**","/layui/**","/scripts/**");
}
}
4.其他类、接口
Token
域
@Component
@Data
public class Token {
private String info;
private String tokenUUID;
}
ITokenService
接口
public interface ITokenService {
boolean addToken(Token token);
String searchToken(String tokenUUID);
}
TokenService
实现类
@Service
public class TokenServiceImpl implements ITokenService {
@Resource
private TokenMapper tokenMapper;
@Override
public boolean addToken(Token token) {
int n=tokenMapper.insert(token);
if (n > 0) {
return true;
}
return false;
}
@Override
public String searchToken(String tokenUUID) {
String s=tokenMapper.selectByToken(tokenUUID);
return s;
}
}
TokenMapper
mapper接口
public interface TokenMapper {
int insert(Token token);
String selectByToken(String tokenUUID);
}
TokenMapper.xml
操作数据库
<mapper namespace="com.zbw.mapper.TokenMapper">
<resultMap id="BaseResultMap" type="java.lang.String">
<result column="username" jdbcType="VARCHAR" property="info"/>
</resultMap>
<insert id="insert" parameterType="com.zbw.domain.Token">
insert into token (username, token)
values (#{info,jdbcType=VARCHAR}, #{tokenUUID,jdbcType=VARCHAR})
</insert>
<select id="selectByToken" parameterType="java.lang.String" resultMap="BaseResultMap">
select username
from token
where token=#{tokenUUID,jdbcType=VARCHAR}
</select>
</mapper>