SpringBoot+Vue+Jpa+Redis实现单点登录(一处登录,另一处退出登录)

SpringBoot+Vue+Redis实现单点登录(一处登录,另一处退出登录)

一、需求

实现用户在浏览器登录后,跳转到其他页面,当用户在其它地方又登录时,前面用户登录的页面退出登录(列如qq挤号那种方式)

二、实现思路

用户在前端填写用户信息登录后,后台接收数据先去数据库进行判断,如果登录成功,创建map集合,以用户id为键,token为值,先通过当前登录用户的id去获取token,如果token存在说明该用户已经登录过,调用redis以token为键删除上个用户的信息,调用方法生成新token,并将token存入map集合,将用户信息存入redis,并将token存入cookie。当用户回到前面登录的页面时,刷新页面,调用方法,通过后端获取cookie的token值,通过token在redis中查询用户信息是否存在,如果不存在,前端通过返回值判断重新回到登录页面!

三、实现代码

后端:
1、创建SpringBoot项目,创建User表,由于是通过Vue编写的,所以是前后端分离,需要跨域,我这里编写了跨域配置类,还有redis的util类,返回的封装类,cookie的util类,文末有源码提供,可以自行提取。
2、yum配置文件

spring:
  redis:
    database: 0    #redis的默认数据库为0
    host: 127.0.0.1  #链接redis的ip
    port: 6379  #链接redis的端口号
    password:   #链接redis的密码 默认为空
    jedis:
      pool:
        max-total: 200    #链接redis的总数目
        max-active: 100  #链接redis的最大
        max-idle: 8      #最大的链接数量
        min-idle: 5     #最小的链接数量
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    show-sql: true
server:
  port: 8888

REDIS_KEY : USER_TOKEN

3、编写实体User.class

@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @Column(name = "id",unique = true,nullable = false)
    private int id;
    @Column(name = "username",nullable = false)
    private  String username;
    @Column(name = "password",nullable = false)
    private String  password;
}

4、编写Dao,UserDao.class

public interface UserDao extends JpaRepository<User,Integer> {
   public User findByUsernameAndPassword(String username, String password);
}

5、编写serviceImpl,UserServiceImpl.class进行登录的业务逻辑处理

@Service
public class UserServiceImpl{
    @Autowired
    private UserDao userDao;
    @Autowired
    private JedisDao jedisDao;
    @Value("${REDIS_KEY}")   //从配置文件中取值
    private String KEY;

    private Map<Integer,String> UserLogin = new HashMap<>();

    /**
     * 登录
     * @param request
     * @param response
     * @param u
     * @return
     */
    public User userlogin(HttpServletRequest request, HttpServletResponse response, User u){
        //查询登录是否成功
        User user=userDao.findByUsernameAndPassword(u.getUsername(),u.getPassword());
        //判断us是否为空
        if(user==null){
            return null;
        }
        //生成token
        String token="user_"+ UUID.randomUUID().toString();
        //从map中获得redis中的key
        String oldToken = UserLogin.get(user.getId());
        //判断map中是否存在该id
        if(!StringUtils.isEmpty(oldToken)){
            //删除redis中老的值
            jedisDao.delValue(oldToken);
        }
        //将新的的key保存到map中
        UserLogin.put(user.getId(),token);
        //将信息存入redis
        jedisDao.setValue(token, JsonUtils.objectToJson(user));
        //将token放入cookie中
        CookieUtils.setCookie(request,response,KEY,token,5*60,true);
        return user;
    }

    /**
     * 判断是否登录
     * @param response
     * @param request
     * @return
     */
    public String getUserByToken(HttpServletResponse response, HttpServletRequest request) {
        //从cookie中取出用户token
        String token=CookieUtils.getCookieValue(request,KEY);
        //从redis中取出用户信息
        String user= jedisDao.getValue(token);
        return user;
    }
}

6、编写controller,接收前端请求,返回数据

@RestController
public class LoginController {

    @Autowired
    private UserServiceImpl userService;

    /**
     * 登录
     * @param response
     * @param request
     * @param user
     * @param model
     * @return
     */
    @PostMapping("/login")
    public ResponseResult Login(HttpServletResponse response , HttpServletRequest request, @RequestBody User user, Model model){
        ResponseResult responseResult=new ResponseResult();
        try {
            User user2 = userService.userlogin(request, response, user);
            if (user2!=null){
                responseResult.setState(200);
                responseResult.setMsg("登录成功!");
                return responseResult;
            }else{
                responseResult.setState(202);
                responseResult.setMsg("用户名或密码错误!");
                return responseResult;
            }
        }catch (Exception e) {
            responseResult.setState(500);
            responseResult.setMsg("发生错误,登录失败!");
            return responseResult;
        }
    }

    /**
     * 判断是否登录
     * @param response
     * @param request
     * @return
     * @throws Exception
     */
    @GetMapping("/toLogin")
    public ResponseResult getUserInfo(HttpServletResponse response , HttpServletRequest request) throws Exception {
        ResponseResult responseResult=new ResponseResult();
        try{
            String token = userService.getUserByToken(response, request);
            if(token!=null){
                responseResult.setState(200);
                responseResult.setMsg("登录中!");
                return responseResult;
            }else{
                responseResult.setState(202);
                responseResult.setMsg("在别处登录!");
                return responseResult;
            }
        }catch (Exception e){
            response.setStatus(500);
            responseResult.setMsg("发生错误!");
            return responseResult;
        }
    }
}

Vue前端
1、创建Vue项目:vue init webpack 项目名称
2、引入axios:npm install --save axios vue-axios
3、引入element:npm i element-ui -S
4、在src的main.js下配置

import axios from 'axios'
import VueAxios from 'vue-axios'
// element-ui 引入文件
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
//注册 VueAxios, axios
Vue.use(VueAxios, axios)
Vue.use(ElementUI)
//配置axios支持cookie
axios.defaults.withCredentials = true;

5、在src的components下创建login.vue,userinfo.vue,并在src的router下配置访问地址

import Vue from 'vue'
import Router from 'vue-router'
import login from '@/components/login'
import UserInfo from '@/components/userinfo'

Vue.use(Router)

export default new Router({
  routes: [{
    path: '/login',
    component: login
  }, {
    path: '/user_info',
    component: UserInfo
  }]

})

6、前端的代码这里就不贴出了,代码是有详细的注释,请自行下载代码查看

四、代码地址和演示效果

登录:
在这里插入图片描述
在这里插入图片描述
下线:
在这里插入图片描述
dome代码地址

链接:https://pan.baidu.com/s/1qm5uktPJAT6pB4SI37s5Vw
提取码:e5hn

该dome仅供参考,如果有什么错误希望可以及时留言指出,谢谢!

发布了13 篇原创文章 · 获赞 48 · 访问量 4297

猜你喜欢

转载自blog.csdn.net/weixin_44209403/article/details/103246743
今日推荐