登录和登录拦截实现
一:前端登录按钮绑定事件发送请求后端接口
//登录按钮
login(ev) {
//点击登录校验
this.$refs.ruleForm2.validate((valid) => {
//校验成功
if (valid) {
this.logining = true; //显示忙等框
//发送axios请求
this.$http.post("/login/account",this.ruleForm2).then(res=>{
this.logining = false;
二:后端接口接收到前端发送的请求与数据
package cn.ybl.user.controller;
import cn.ybl.basic.exception.BusinessException;
import cn.ybl.basic.util.AjaxResult;
import cn.ybl.user.dto.LoginDto;
import cn.ybl.user.service.ILoginInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @Author Mr.Yang
* @createTime 2022/7/29 17:09
* @Describe 登录接口
*/
@RestController
@RequestMapping("/login")
public class LoginController {
@Autowired
private ILoginInfoService loginInfoService;
/**
* 账号登录
* @param loginDto
* @return AjaxResult
*/
@PostMapping("/account")
public AjaxResult accountLogin(@RequestBody LoginDto loginDto){
try {
Map<String, Object> map = loginInfoService.accountLogin(loginDto);
return AjaxResult.getResult().setResultObj(map);
}
catch (BusinessException e) {
e.printStackTrace();
return AjaxResult.getResult().setMsg(e.getMessage());
}
catch (Exception e) {
e.printStackTrace();
return AjaxResult.getResult().setMsg("系统异常,请稍后重试");
}
}
}
三:业务层对传递过来的数据进行校验,并与数据库中的数据进行比对,比对失败直接抛异常终止程序运行,比对成功则通过UUID生成一个token,与查询出来的对象一起设置进Redis,并将token和对象返回给前端,为了安全,要把密码和盐值去掉
package cn.ybl.user.service.impl;
import cn.ybl.basic.exception.BusinessException;
import cn.ybl.basic.service.impl.BasicServiceImpl;
import cn.ybl.basic.util.Md5Utils;
import cn.ybl.user.domain.LoginInfo;
import cn.ybl.user.dto.LoginDto;
import cn.ybl.user.mapper.LoginInfoMapper;
import cn.ybl.user.service.ILoginInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @Author Mr.Yang
* @createTime 2022/7/26 10:45
* @Describe 登录用户信息表Service实现类
*/
@Service
public class LoginInfoServiceServiceImpl extends BasicServiceImpl<LoginInfo> implements ILoginInfoService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private LoginInfoMapper loginInfoMapper;
/**
* 修改激活属性
* @param id
*/
@Override
public void activation(Long id) {
loginInfoMapper.activation(id);
}
/**
* 根据手机号或邮箱和类型登录
* @param loginDto
* @return Map
*/
@Override
public Map<String, Object> accountLogin(LoginDto loginDto) {
//判空
if(StringUtils.isEmpty(loginDto.getPhone())){
throw new BusinessException("请输入账号");
}
if(StringUtils.isEmpty(loginDto.getPassword())){
throw new BusinessException("请输入密码");
}
if(StringUtils.isEmpty(loginDto.getLoginType())){
throw new BusinessException("请选择登录身份");
}
//校验账号【根据用户名、手机号和type查询】
LoginInfo loginInfo = loginInfoMapper.accountLogin(loginDto);
if(loginInfo==null){
throw new BusinessException("用户或密码错误");
}
//判断账号是否激活
if("0".equals(loginInfo.getDisable())){
throw new BusinessException("您的账号已禁用,请联系管理员");
}
//验证密码是否正确
String password = loginDto.getPassword(); //获取输入的密码
String salt = loginInfo.getSalt(); //获取查询出来的对象的盐值
String md5Pwd = Md5Utils.encrypByMd5(password + salt); //加密加盐进行对比密码
if(!loginInfo.getPassword().equals(md5Pwd)){
throw new BusinessException("用户或密码错误");
}
//通过uuid获取一个随机的key
String token = UUID.randomUUID().toString();
//将对象和key存入redis并设置30分钟有效
redisTemplate.opsForValue().set(token,loginInfo,30, TimeUnit.MINUTES);
Map<String, Object> map = new HashMap<>();
map.put("token",token);
loginInfo.setPassword(null);
loginInfo.setSalt(null);
map.put("logininfo",loginInfo);
//将map返回给前端
return map;
}
}
四:前端判断返回的数据是否登录成功,成功则拿到返回的对象和token后通过JSON.stringify转为json对象存入localStorage【拦截器要用,判断登录状态】
//登录按钮
login(ev) {
//点击登录校验
this.$refs.ruleForm2.validate((valid) => {
//校验成功
if (valid) {
this.logining = true; //显示忙等框
//发送axios请求
this.$http.post("/login/account",this.ruleForm2).then(res=>{
this.logining = false;
//登陆成功
if(res.data.success){
this.$message.success("登录成功,即将跳转后台首页")
//将后台传递的resultObj的token和登录对象信息存入localStorage
var token = res.data.resultObj.token
var logininfo = res.data.resultObj.logininfo
localStorage.setItem("token",token)
localStorage.setItem("logininfo",JSON.stringify(logininfo))
//跳转页面
this.$router.push({ path: '/echarts' });
}
//登陆失败
else{
this.$message.error(res.data.msg)
}
}).catch(res=>{
this.$message.error("系统繁忙")
})
}
//校验失败
else {
this.$message({
message:"请检查你输入的数据!",
type:"error",
})
return false
}
});
}
到此登录完成
五:前端——axios请求拦截器
请求拦截器拦截一切axios请求,它的任务是从localStorage中获得token并将它放进请求头中,以供后端取出做校验
//===============================axios请求拦截器【发请求前将token加到请求头】===============================
axios.interceptors.request.use(res=>{
let token = localStorage.getItem("token");
if(token){
res.headers["token"] = token;
}
return res;
},error => {
Promise.reject(error)
})
六:前端——axios响应拦截器
响应拦截器在后端响应数据后执行,它的任务是比对后端MVC拦截器拦截到的非法请求返回的json数据,作出反应
//===============================axios响应拦截器===============================
axios.interceptors.response.use(res => {
//没登陆或者过期
if (false === res.data.success || "noLogin" === res.data.msg) {
localStorage.removeItem("token");
localStorage.removeItem("logininfo");
router.push({path: '/login'});
}
return res;
},error => {
Promise.reject(error)
})
七:前端——路由拦截器
路由拦截器在前端发送请求时拦截,它从localStorage中获取token,存在则放行,不存在则拦截请求
//===============================路由拦截器【静态资源拦截器】===============================
router.beforeEach((to, from, next) => {
//跳转登录注册页面清空localStorage
if (to.path == '/login' || to.path == "/register") {
localStorage.removeItem("token");
localStorage.removeItem("logininfo");
next();//放行
}else{
//判断是否登录
let logininfo = localStorage.getItem('logininfo');
if (logininfo) {
next();
} else {
next({path: '/login'});//跳转到login
}
}
})
八:后端——SpringMVC拦截器
Springboot实现SpringMVC拦截器由拦截器类和配置类组成
拦截器类:【负责拦截逻辑处理,从请求头中获取头信息,通过Redis判断是否失效,失效则返回json,没失效则刷新过期时间】
package cn.ybl.basic.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;
/**
* @Author Mr.Yang
* @createTime 2022/7/30 14:49
* @Describe 登录拦截器
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取请求头中的数据
String token = request.getHeader("token");
if(token!=null){
//根据请求头key在Redis中取值
Object logininfo = redisTemplate.opsForValue().get(token);
if(logininfo!=null){ //说明没过期
//重新设置过期时间
redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
//放行
return true;
}
}
//请求头中没有数据或者登录信息过期了==============进行拦截
//手动拼接一个json数据返回给前端
response.setContentType("application/json;charset=utf8");
response.getWriter().write("{\"success\":false,\"msg\":\"nologin\"}");
return false;
}
}
拦截器配置类:【负责配置拦截的具体请求,相当于SSM的xml】
package cn.ybl.basic.interceptor.config;
import cn.ybl.basic.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author Mr.Yang
* @createTime 2022/7/30 15:38
* @Describe 拦截器配置类【配置拦截的请求】
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
//拦截所有请求
.addPathPatterns("/**")
//放行登录请求
.excludePathPatterns("/logins/**")
//放行注册请求
.excludePathPatterns("/register/**")
//放行fastdfs请求
.excludePathPatterns("/fastDfs/**")
//放行图形验证码请求
.excludePathPatterns("/verifyCode/**")
//放行店铺入驻
.excludePathPatterns("/shop/settlement")
//放行swagger
.excludePathPatterns("//swagger-resources/**\", \"/webjars/**\", \n" +
" \"/v2/**\", \"/swagger-ui.html/**");
}
}
到此登录拦截完成

浙公网安备 33010602011771号