• Ruo-Yi前后端分离相关笔记


    1.前提条件和基础

    Spring Boot +Vue

    环境要求:Jdk1.8以上版本、MySql数据库、Redis、Maven、Vue

    2.使用若依

    官网地址:RuoYi-Vue: 🎉 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统,同时提供了 Vue3 的版本 (gitee.com)

    2.1下载

    目录:

    2.2配置数据库MySQL和Redis

    2.2.1MySQL数据库配置

    MySQL配置后的效果:

    在工程中配置数据库(改为本地数据库):

    2.2.2Redis配置

    2.3运行原始项目

    2.3.1后端

    打开浏览器,访问8080端口,出现如下,则访问成功:

    2.3.2启动前端

    1.安装依赖

    2运行前端

    若Node.js版本高,则需要在package.json中修改配置:

    1. "scripts": {
    2. "dev": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
    3. "build:prod": "vue-cli-service build",
    4. "build:stage": "vue-cli-service build --mode staging",
    5. "preview": "node build/index.js --preview",
    6. "lint": "eslint --ext .js,.vue src"
    7. }

    运行成功后:

    3.相关功能实现

    3.1登录

    3.1.1生成验证码

    基本思路:后端生成一个表达式,例如:2+2=?@4,然后把题干2+2=?生成图片、和一个唯一的key传到前端;把结果4(value),和唯一的key做键存到redis。

    3.1.1.1前端相关代码

    1.页面中的函数相关代码(login.vue):

    2.获取验证码的请求封装(api/login.js):

    统一的请求前缀:

    3.利用反向代理,url请求前端,进行代理,映射转发到后端,用于解决跨域问题。代理的配置部分在:

    达到的效果:http:localhost/dev-api/captcheImage   ---->http:localhost/captcheImage

    3.1.1.2后端相关代码

    1. /**
    2. * 生成验证码
    3. */
    4. @GetMapping("/captchaImage")
    5. public AjaxResult getCode(HttpServletResponse response) throws IOException
    6. {
    7. AjaxResult ajax = AjaxResult.success();
    8. boolean captchaEnabled = configService.selectCaptchaEnabled();//判断是否开启验证
    9. ajax.put("captchaEnabled", captchaEnabled);
    10. if (!captchaEnabled)
    11. {
    12. return ajax;
    13. }
    14. // 保存验证码信息
    15. String uuid = IdUtils.simpleUUID();
    16. String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
    17. String capStr = null, code = null;
    18. BufferedImage image = null;
    19. // 生成验证码
    20. String captchaType = RuoYiConfig.getCaptchaType();
    21. if ("math".equals(captchaType))
    22. {
    23. String capText = captchaProducerMath.createText();
    24. capStr = capText.substring(0, capText.lastIndexOf("@"));
    25. code = capText.substring(capText.lastIndexOf("@") + 1);
    26. image = captchaProducerMath.createImage(capStr);
    27. }
    28. else if ("char".equals(captchaType))
    29. {
    30. capStr = code = captchaProducer.createText();
    31. image = captchaProducer.createImage(capStr);
    32. }
    33. redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
    34. // 转换流信息写出
    35. FastByteArrayOutputStream os = new FastByteArrayOutputStream();
    36. try
    37. {
    38. ImageIO.write(image, "jpg", os);
    39. }
    40. catch (IOException e)
    41. {
    42. return AjaxResult.error(e.getMessage());
    43. }
    44. ajax.put("uuid", uuid);
    45. ajax.put("img", Base64.encode(os.toByteArray()));
    46. return ajax;
    47. }

    3.1.2登录的实现

    3.1.2.1前端相关代码

    vuex全局对象:

    请求封装:

    3.1.2.2后端相关代码

    from:com.ruoyi.framework.web.service

    1. public String login(String username, String password, String code, String uuid)
    2. {
    3. // 验证码校验
    4. validateCaptcha(username, code, uuid);
    5. // 登录前置校验
    6. loginPreCheck(username, password);
    7. // 用户验证
    8. Authentication authentication = null;
    9. try
    10. {
    11. UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
    12. AuthenticationContextHolder.setContext(authenticationToken);
    13. // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
    14. authentication = authenticationManager.authenticate(authenticationToken);
    15. }
    16. catch (Exception e)
    17. {
    18. if (e instanceof BadCredentialsException)
    19. {
    20. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
    21. throw new UserPasswordNotMatchException();
    22. }
    23. else
    24. {
    25. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
    26. throw new ServiceException(e.getMessage());
    27. }
    28. }
    29. finally
    30. {
    31. AuthenticationContextHolder.clearContext();
    32. }
    33. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
    34. LoginUser loginUser = (LoginUser) authentication.getPrincipal();
    35. recordLoginInfo(loginUser.getUserId());
    36. // 生成token
    37. return tokenService.createToken(loginUser);
    38. }

    1.验证码校验(validateCaptcha(String username, String code, String uuid))

    2.登录前置校验

    1. /**
    2. * 登录前置校验
    3. * @param username 用户名
    4. * @param password 用户密码
    5. */
    6. public void loginPreCheck(String username, String password)
    7. {
    8. // 用户名或密码为空 错误
    9. if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
    10. {
    11. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
    12. throw new UserNotExistsException();
    13. }
    14. // 密码如果不在指定范围内 错误
    15. if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
    16. || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
    17. {
    18. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
    19. throw new UserPasswordNotMatchException();
    20. }
    21. // 用户名不在指定范围内 错误
    22. if (username.length() < UserConstants.USERNAME_MIN_LENGTH
    23. || username.length() > UserConstants.USERNAME_MAX_LENGTH)
    24. {
    25. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
    26. throw new UserPasswordNotMatchException();
    27. }
    28. // IP黑名单校验
    29. String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
    30. if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
    31. {
    32. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
    33. throw new BlackListException();
    34. }
    35. }

    3.用户验证并生成Token

    3.1.3getInfo:获取当前用户的角色和权限信息,存储到Vuex中

    3.1.4getRouters:根据当前用户的权限获取动态路由

  • 相关阅读:
    自托管书签管理器LinkAce
    七夕送女朋友什么礼物?2022年七夕礼物推荐
    h3c 网络设备清理所有配置
    什么是数据库?数据库有哪些基本分类和主要特点?
    MySQL-存储引擎
    【云原生】DevOps(五):集成Harbor
    一文1800字解读性能指标与性能分析
    【第97题】JAVA高级技术-网络编程16(简易聊天室11:实现客户端群聊)
    Simulink仿真之离散系统
    Leetcode力扣 MySQL数据库 1841 联赛信息统计
  • 原文地址:https://blog.csdn.net/weixin_47219891/article/details/133946300