本文主要写RuoYi项目前端登录流程

后端包含ruoyi-admin,ruoyi-common,ruoyi-framework等多个模块,ruoyi-admin为启动模块。先看一下ruoyi-admin/src/main/application.yml配置文件。

# 开发环境配置
server:# 服务器的HTTP端口,默认为8080port: 8080

指定了服务端启动的端口8080。我们运行ruoyi-admin/src/main/java/com/ruoyi/
RuoYiApplication.java即可启动后端,监听8080端口。
我们回到前端的登录界面。 views/login.vue

<template><div class="login"><el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"><h3 class="title">若依后台管理系统</h3><el-form-item prop="username"><el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"><svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /></el-input></el-form-item><el-form-item prop="password"><el-inputv-model="loginForm.password"type="password"auto-complete="off"placeholder="密码"@keyup.enter.native="handleLogin"><svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /></el-input></el-form-item><el-form-item prop="code"><el-inputv-model="loginForm.code"auto-complete="off"placeholder="验证码"style="width: 63%"@keyup.enter.native="handleLogin"><svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /></el-input><div class="login-code"><img :src="codeUrl" @click="getCode" class="login-code-img"/></div></el-form-item><el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox><el-form-item style="width:100%;"><el-button:loading="loading"size="medium"type="primary"style="width:100%;"@click.native.prevent="handleLogin"><span v-if="!loading">登 录</span><span v-else>登 录 中...</span></el-button></el-form-item></el-form><!--  底部  --><div class="el-login-footer"><span>Copyright © 2018-2020 ruoyi.vip All Rights Reserved.</span></div></div>
</template><script>import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt'export default {name: "Login",data() {return {codeUrl: "",cookiePassword: "",loginForm: {username: "admin",password: "admin123",rememberMe: false,code: "",uuid: ""},loginRules: {username: [{ required: true, trigger: "blur", message: "用户名不能为空" }],password: [{ required: true, trigger: "blur", message: "密码不能为空" }],code: [{ required: true, trigger: "change", message: "验证码不能为空" }]},loading: false,redirect: undefined};},watch: {$route: {handler: function(route) {this.redirect = route.query && route.query.redirect;},immediate: true}},created() {this.getCode();this.getCookie();},methods: {getCode() {getCodeImg().then(res => {this.codeUrl = "data:image/gif;base64," + res.img;this.loginForm.uuid = res.uuid;});},getCookie() {const username = Cookies.get("username");const password = Cookies.get("password");const rememberMe = Cookies.get('rememberMe')this.loginForm = {username: username === undefined ? this.loginForm.username : username,password: password === undefined ? this.loginForm.password : decrypt(password),rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)};},handleLogin() {this.$refs.loginForm.validate(valid => {if (valid) {this.loading = true;if (this.loginForm.rememberMe) {Cookies.set("username", this.loginForm.username, { expires: 30 });Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });} else {Cookies.remove("username");Cookies.remove("password");Cookies.remove('rememberMe');}this.$store.dispatch("Login", this.loginForm).then(() => {this.$router.push({ path: this.redirect || "/" });}).catch(() => {this.loading = false;this.getCode();});}});}}
};</script>

页面加载前,created()调用this.getCode()和this.getCookie()获取验证码和cookie。这里不详细说明。我们重点关注下handleLogin登录函数。this. r e f s . l o g i n F o r m . v a l i d a t e 判 断 用 户 名 、 密 码 和 验 证 码 的 合 法 性 。 t h i s . l o g i n F o r m . r e m e m b e r M e 判 断 是 否 选 择 了 记 住 密 码 。 如 果 记 住 密 码 , 我 们 把 用 户 名 密 码 存 进 c o o k i e , 下 次 跳 到 登 录 界 面 就 不 需 要 输 用 户 名 密 码 。 如 果 不 选 择 记 住 密 码 , 将 清 空 c o o k i e , 下 次 跳 到 登 录 界 面 需 要 手 动 输 入 用 户 名 和 密 码 。 t h i s . refs.loginForm.validate判断用户名、密码和验证码的合法性。this.loginForm.rememberMe判断是否选择了记住密码。如果记住密码,我们把用户名密码存进cookie,下次跳到登录界面就不需要输用户名密码。如果不选择记住密码,将清空cookie,下次跳到登录界面需要手动输入用户名和密码。 this. refs.loginForm.validatethis.loginForm.rememberMecookiecookiethis.store.dispatch(“Login”, this.loginForm),这里是我们最需要关注的地方。调用store里的Login对应的函数,把loginForm作为参数。我们跳到src/store/modules/user.js。

import { login, logout, getInfo } from '@/api/login'
......
actions: {// 登录Login({ commit }, userInfo) {const username = userInfo.username.trim()const password = userInfo.passwordconst code = userInfo.codeconst uuid = userInfo.uuidreturn new Promise((resolve, reject) => {login(username, password, code, uuid).then(res => {setToken(res.token)commit('SET_TOKEN', res.token)resolve()}).catch(error => {reject(error)})})},......}

这里新建了一个Promise,调用了login函数,login函数是从@/api/login引入的。我们再跳到src/api/login.js看一下这个函数:

// 登录方法
export function login(username, password, code, uuid) {const data = {username,password,code,uuid}return request({url: '/login',method: 'post',data: data})
}

这里构建了一个ajax的POST请求,url为/login,data为用户名、密码、验证码的结构数据。我们再简单看一下request对应的src/utils/request.js。

// 创建axios实例
const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: process.env.VUE_APP_BASE_API,// 超时timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {// 是否需要设置 tokenconst isToken = (config.headers || {}).isToken === falseif (getToken() && !isToken) {config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改}return config
}, error => {console.log(error)Promise.reject(error)
})

我们看到请求的地址是process.env.VUE_APP_BASE_API, 这是怎么访问到后端的的呢?我们回头看一下vue.config.js文件

devServer: {host: '0.0.0.0',port: port,open: true,proxy: {// detail: https://cli.vuejs.org/config/#devserver-proxy[process.env.VUE_APP_BASE_API]: {target: `http://localhost:8080`,changeOrigin: true,pathRewrite: {['^' + process.env.VUE_APP_BASE_API]: ''}}},disableHostCheck: true},

这里做了一个代理,把process.env.VUE_APP_BASE_API地址映射成了http://localhost:8080。所以我们login最终访问后端的地址就变为http://localhost:8080/login。
现在看一下后端接收这个请求的代码。ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java。

 /*** 登录方法* * @param loginBody 登录信息* @return 结果*/@PostMapping("/login")public AjaxResult login(@RequestBody LoginBody loginBody){AjaxResult ajax = AjaxResult.success();// 生成令牌String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),loginBody.getUuid());ajax.put(Constants.TOKEN, token);return ajax;}

接收到/login的POST请求后,调用loginService.login方法进行验证,并生成token返回给客户端。接下来,看一下loginService.login方法。

/*** 登录验证* * @param username 用户名* @param password 密码* @param code 验证码* @param uuid 唯一标识* @return 结果*/public String login(String username, String password, String code, String uuid){......// 该方法会去调用UserDetailsServiceImpl.loadUserByUsernameauthentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));......LoginUser loginUser = (LoginUser) authentication.getPrincipal();// 生成tokenreturn tokenService.createToken(loginUser);}

这里牵扯到Spring Security 的知识,我们看一下Spring Security的配置ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java。

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{ /*** 身份认证接口*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception{auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());}
}

这里设置了userDetailService。UserDetailsServiceImpl实现了UserDetailService接口,实现了loadUserByUsername方法。我们再看一下UserDetailsServiceImpl.loadUserByUsername的实现:

@Service
public class UserDetailsServiceImpl implements UserDetailsService
{
@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{SysUser user = userService.selectUserByUserName(username);if (StringUtils.isNull(user)){log.info("登录用户:{} 不存在.", username);throw new UsernameNotFoundException("登录用户:" + username + " 不存在");}else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())){log.info("登录用户:{} 已被删除.", username);throw new BaseException("对不起,您的账号:" + username + " 已被删除");}else if (UserStatus.DISABLE.getCode().equals(user.getStatus())){log.info("登录用户:{} 已被停用.", username);throw new BaseException("对不起,您的账号:" + username + " 已停用");}return createLoginUser(user);}}

就是根据用户名去数据库查询用户信息并返回。然后 再调用Spring Security内部的认证代码进行认证。

protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {if (authentication.getCredentials() == null) {this.logger.debug("Authentication failed: no credentials provided");throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));} else {String presentedPassword = authentication.getCredentials().toString();if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {this.logger.debug("Authentication failed: password does not match stored value");throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));}}}

就是比较根据用户名获取到的用户的密码和认证信息参数中的密码进行比较。更为详细的过程,这里引用了一位大神的文章,介绍的很详细。
https://blog.csdn.net/yuanlaijike/article/details/84703690
认证完成后,根据用户的信息,构建token,进行返回。前端收到返回后,存储token,并跳转网页。this.$router.push({ path: this.redirect || “/” });

Ruoyi若依前后端分离框架【若依登录详细过程】相关推荐

  1. 若依前后端分离框架去掉首页 登录后跳转至动态路由的第一个路由

    若依前后端分离框架去掉首页 登录后跳转至动态路由的第一个路由 若依框架VUE前端界面,登录后默认跳转至动态路由第一路由(第一个子菜单) 一.登录后跳转第一路由界面 二.设置路由的首页路径,方便后续的获 ...

  2. 搭建spring-boot+vue前后端分离框架并实现登录功能

    一.环境.工具 jdk1.8 maven spring-boot idea VSVode vue 二.搭建后台spring-boot框架 步骤: 1.new- project选择Spring Init ...

  3. java通过Excel 模板导出复杂统计类excel文档,在ruoyi前后端分离框架中的应用

    Hello, 大家好! 我是不作死就不会死,智商不在线,但颜值超有品的拆家队大队长 --咖啡汪 一只不是在戏精,就是在戏精路上的极品二哈 前几天刚做了java通过Excel 模板导出复杂统计类exce ...

  4. 若依前后端分离框架学习-2:登录过程

    上一篇写了下若依前后端分离框架中前端至弹出登陆界面的过程,本片来详细了解下登录的整个过程.     后端包含ruoyi-admin,ruoyi-common,ruoyi-framework等多个模块, ...

  5. 若依前后端分离框架集成websocket

    1. 若依不分离框架集成websocket可以参照http://doc.ruoyi.vip/ruoyi/document/cjjc.html#%E9%9B%86%E6%88%90websocket%E ...

  6. 若依前后端分离框架部署Linux服务器

    若依前后端分离框架部署Linux服务器 第一次使用若依框架进行部署Linux服务器,出现了很多的问题,也可能是自身对若依框架的不太熟悉导致接下来说一下我的部署 第一步:首先我们把我们的前端打包,如果不 ...

  7. Angular4+AdminLTE+Jeecg 前后端分离框架实战-张代浩-专题视频课程

    Angular4+AdminLTE+Jeecg 前后端分离框架实战-2259人已学习 课程介绍         Angular4+AdminLTE+Jeecg 前后端分离框架实战 涉及技术点:angu ...

  8. vue-element-admin/template+tornado(pyrestful)前后端分离框架实践(1)——自定义菜单和仪表盘

    0. 写在前面 vue-element-admin 是一个后台前端解决方案,它基于 vue 和 element-ui实现.它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证, ...

  9. 若依前后端分离框架学习-6:日志管理

    这一章,我们来学习下若依前后端分离框架中的日志管理.学习自定义注解的使用.     我们编辑一下"测试子模块"中张三这条数据.然后查看下操作日志.     这里我们看到,编辑的日志 ...

最新文章

  1. Udacity机器人软件工程师课程笔记(五)-样本搜索和找回-基于漫游者号模拟器-自主驾驶
  2. P2P最易遭受的DDoS***以及防御手段
  3. 使用 go 实现 Proof of Stake 共识机制
  4. 惯性传感器的卡尔曼滤波
  5. 【LeetCode算法题库】Day5:Roman to Integer Longest Common Prefix 3Sum
  6. 计算机的硬件工作原理(图片部分资源摘自王道考研资料)
  7. SpringBoot+MyBatis启动报错java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal
  8. python—itertools模块常用函数
  9. 字符串数组排序,如果可以保证前一个字符的末尾与后一个字符的开头相同,返回1,否则返回-1...
  10. 如何在 FaceTime 通话中共享您的屏幕?
  11. 《Head First Servlets JSP》-11-Web应用部署
  12. 学校管理系统java(数据库、源码、演讲内容、ppt等)
  13. php立方体相册源码,制作三维电子相册 3d立方体相册制作(flash相册制作)
  14. TIA Openness开发入门(2)
  15. Listary——好用到哭的高效快速搜索工具
  16. 0xc0000001报错解决办法
  17. ssm + layui + poi+ 自定义注解 + java反射 做条件导出Excel 工具类
  18. JavaScript - 运算符与表达式
  19. 万年历设计单片机c语言,数字万年历设计(80c51单片机、时钟芯片ds1320).pdf
  20. 【功能安全】【ISO26262】整体介绍

热门文章

  1. 2009年我国报刊发行创新的五个关键词
  2. 居家办公的团队协作模式改进思考
  3. 通过爬虫获取第五人格游戏信息整理并分析(一)
  4. 比Linken Sphere(林肯法球)更多更新浏览器指纹的国产防关联工具-VMLogin中文版
  5. linux灯控软件,Ubuntu下通过脚本控制键盘背光灯
  6. 攻防世界之互相伤害!!!
  7. STM32F407VET6 / BLACK_F407VE开发板间隔0.5秒不断重启
  8. Win10自带的录屏功能怎么用?
  9. 使用R语言画火山图详细步骤
  10. 计算机二级office考试题库操作题,计算机二级考试MSOffice考试题库ppt操作题附答案...