SpringBoot+Vue+Redis实现前后端分离的单点登录

一、需求分析
用户在浏览器登录后,跳转到其他页面,当用户在其他地方再次登录时,前一个页面自动退出登录,列如游戏或者qq挤号,显示该账号已经在另外的地方登录。
二、开始编写后端代码
1、创建数据库表并新增两条数据,用于测试

CREATE DATABASE
USE `login`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
//密码进行了MD5加密,更换了以前的未加密的密码
insert  into `user`(`id`,`username`,`password`) values 
(1,'root','63a9f0ea7bb98050796b649e85481845'),
(2,'admin','e10adc3949ba59abbe56e057f20f883e');
//root的password为 root
//admin的password为 123456

2、创建SpringBoot项目,项目结构如下,(截图的水印不晓得怎么去掉,就这样吧)
SpringBoot+Vue+Redis实现前后端分离的单点登录_第1张图片
3、修改pom.xml,添加相关依賴

 		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
            <groupId>org.apache.directory.studio</groupId>
            <artifactId>org.apache.commons.lang</artifactId>
            <version>2.6</version>
        </dependency>

4、开始配置application.yml

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:
  #由于买的阿里云服务器内存不够了,docker容器中mysql镜像总是自动关闭,所以改用本地mysql
    url: jdbc:mysql://127.0.0.1:3306/login?useUnicode=true
    username: root
    password: sasa
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    show-sql: true
server:
  port: 8888
REDIS_KEY : USER_TOKEN

5、编写用户实体类

@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    @Column(name = "username")
    private  String username;
    @Column(name = "password")
    private String  password;
}

6、编写dao层

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

7、编写service层

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

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

    /**
     * 登录
     */
    public User userlogin(HttpServletRequest request, HttpServletResponse response, User u){
        //查询登录是否成功
        User user=userDao.findByUsernameAndPassword(u.getUsername(),u.getPassword());
        //判断us是否为空
        if(user==null){
            return null;
        }
        //调用MD5方法进行加密
        String pwd=string2MD5(user.getPassword());
        System.out.println("测试md5加密:"+pwd);

        System.out.println("测试us对象密码"+us.getPassword());
        //如果加密密码和未加密密码不一致,则返回null
        if(!pwd.equals(us.getPassword())){
            System.out.println("测试:现加密密码和数据库内加密密码不一致");
            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;
    }

    /**
     * 判断是否登录
     */
    public String getUserByToken(HttpServletResponse response, HttpServletRequest request) {
        //从cookie中取出用户token
        String token=CookieUtils.getCookieValue(request,KEY);
        //从redis中取出用户信息
        String user= jedisDao.getValue(token);
        return user;
    }
    
 	/***
     * MD5加码 生成32位md5码
     */
    public  String string2MD5(String inStr){
        MessageDigest md5 = null;
        try{
            md5 = MessageDigest.getInstance("MD5");
        }catch (Exception e){
            System.out.println(e.toString());
            e.printStackTrace();
            return "";
        }
        char[] charArray = inStr.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++){
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16)
                hexValue.append("0");
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }
}

8、编写controller层

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    /**
     * 登录验证
     */
    @PostMapping("/userLogin")
    public ResponseResult userLogin(HttpServletRequest req, HttpServletResponse resp, @RequestBody User user){
        ResponseResult result =new ResponseResult();
        try {
            User userLogin = userService.login(req,resp,user);
            if(userLogin==null){
                result.setMsg("用户名或者密码不正确");
            }else{
                System.out.println("登录成功,测试输出userLogin"+userLogin);
                result.setData(userLogin);
            }
            return result;//将数据传到前端
        }catch (Exception e){
            e.printStackTrace();
            result.setState(500);
            result.setMsg("登录失败,用户名或密码错误");
            return result;
        }
    }

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

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、前端vue代码连接
https://pan.baidu.com/s/1An-oJrdLakdKDQ1OXmVyEg
提取码:at5h
前端代码仅供参考,如果有什么错误希望可以及时留言指出,谢谢!

你可能感兴趣的:(SpringBoot+Vue+Redis实现前后端分离的单点登录)