若依实现第三方登录通用方法——手机号登录测试
1. 新增LoginAuthenticationToken类,继承AbstractAuthenticationToken
这个直接复制就好了,更换包名,其他不用进行修改
package com.ruoyi.framework.handler;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;
import java.util.Collection;
public class LoginAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 550L;
private final Object principal;
private Object credentials;
public LoginAuthenticationToken(Object principal, Object credentials) {
super((Collection) null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false);
}
public LoginAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
}
public Object getCredentials() {
return this.credentials;
}
public Object getPrincipal() {
return this.principal;
}
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
super.setAuthenticated(false);
}
public void eraseCredentials() {
super.eraseCredentials();
this.credentials = null;
}
}
2. 创建LoginAuthenticationProvider类,继承AuthenticationProvider
这个直接复制就好了,更换包名,其他不用进行修改
package com.ruoyi.framework.handler;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
@Log4j2
public class LoginAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
public LoginAuthenticationProvider(UserDetailsService userDetailsService) {
setUserDetailsService(userDetailsService);
}
/**
* 重写authentication方法,实现身份验证逻辑
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
LoginAuthenticationToken authenticationToken = (LoginAuthenticationToken) authentication;
String phone = (String) authenticationToken.getPrincipal();
String loginType = (String) authenticationToken.getCredentials();
//委托 UserDetailsService 查找系统用户
UserDetails userDetails = userDetailsService.loadUserByUsername(phone);
//鉴权成功,返回一个拥有鉴权的AbstractAuthenticationToken
LoginAuthenticationToken authenticationTokenRes = new LoginAuthenticationToken(userDetails, userDetails.getAuthorities());
authenticationTokenRes.setDetails(authenticationToken.getDetails());
return authenticationTokenRes;
}
/**
* 重写supports方法,指定此AuthenticationProvider 仅支持短信验证码身份验证
*/
@Override
public boolean supports(Class<?> authentication) {
return LoginAuthenticationToken.class.isAssignableFrom(authentication);
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
3. 创建UserDetailsByOtherLoginServiceImpl实现类,直接复制不用改
位置:com.ruoyi.framework.web.service
重点:@Service(“userDetailsByOtherLogin”) 注解别忘了
package com.ruoyi.framework.web.service;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* 用户验证处理
*
* @author yizhi
*/
@Service("userDetailsByOtherLogin")
public class UserDetailsByOtherLoginServiceImpl implements UserDetailsService {
private static final Logger log = LoggerFactory.getLogger(UserDetailsByOtherLoginServiceImpl.class);
@Autowired
private ISysUserService userService;
@Autowired
private SysPermissionService permissionService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser user = userService.selectUserByUserName(username);
if (StringUtils.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username + " 不存在");
} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
log.info("登录用户:{} 已被删除.", user.getUserName());
throw new ServiceException("对不起,您的账号:" + user.getUserName() + " 已被删除");
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", user.getUserName());
throw new ServiceException("对不起,您的账号:" + user.getUserName() + " 已停用");
}
return createLoginUser(user);
}
public UserDetails createLoginUser(SysUser user) {
return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
}
}
4. 修改UserDetailsServiceImpl实现类,添加@Service(“userDetailsByPassword”)注解
位置:package com.ruoyi.framework.web.service
5. 修改SecurityConfig文件,修改后3和4才会生效
位置:com.ruoyi.framework.config
原有的userDetailsService上面添加个注解 @Qualifier(“userDetailsByPassword”) :这个是用来对应4的@Service(“userDetailsByPassword”) 注解的
添加userDetailsByOtherLoginService并在上面添加注解@Qualifier(“userDetailsByOtherLogin”):这个是用来对应3的@Service(“userDetailsByOtherLogin”)
身份认证接口上添加其他登录方式的验证,具体代码见下方
package com.ruoyi.framework.config;
/**
* spring security配置
*
* @author ruoyi
*/
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 自定义用户认证逻辑
*/
@Autowired
@Qualifier("userDetailsByPassword")
private UserDetailsService userDetailsService;
/**
* 自定义用户认证逻辑
*/
@Autowired
@Qualifier("userDetailsByOtherLogin")
private UserDetailsService userDetailsByOtherLoginService;
==================================
没有修改的地方省略了
==================================
/**
* 身份认证接口
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//其他登录方式的验证
auth.authenticationProvider(new LoginAuthenticationProvider(userDetailsByOtherLoginService));
//账号密码的验证
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
到此第三方登录的配置就完成了,接下来我们创建策略模式+工厂模式,简化后续接入其他第三方代码的成本
1. 创建工厂类
package com.ruoyi.framework.handler;
/**
* 定义上下文
*
* @author yizhi
*/
@Component
public class LoginContext implements InitializingBean, ApplicationContextAware {
private ApplicationContext appContext;
private final Map<String, LoginStrategy> payStrategyHandlerMap = new HashMap<>();
public LoginStrategy getHandler(String type) {
return payStrategyHandlerMap.get(type);
}
@Override
public void afterPropertiesSet() throws Exception {
Collection<LoginStrategy> values = appContext.getBeansOfType(LoginStrategy.class).values();
values.forEach(loginStrategy -> payStrategyHandlerMap.put(loginStrategy.getLoginType(), loginStrategy));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
appContext = applicationContext;
}
}
2. 创建策略接口
getLoginType:用来根据类型进行不同的策略
login:在上个类型的基础上执行登录获取token
package com.ruoyi.framework.handler;
/**
* 登录策略接口
*
* @author yizhi
*/
public interface LoginStrategy {
/**
* 类型
*/
String getLoginType();
/**
* 登录
*
* @param username
* @param password
* @param code
* @return
*/
String login(String username, String password, String code, String uuid);
}
3. 实现策略
a. 抽出密码登录中不需要修改的部分为公共类
package com.ruoyi.framework.handler;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Log4j2
@Component
public class LoginHanlder {
@Autowired
private ISysUserService userService;
@Resource
private AuthenticationManager authenticationManager;
@Autowired
private TokenService tokenService;
/**
* 记录登录信息
*
* @param userId 用户ID
*/
public void recordLoginInfo(Long userId) {
SysUser sysUser = new SysUser();
sysUser.setUserId(userId);
sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
sysUser.setLoginDate(DateUtils.getNowDate());
userService.updateUserProfile(sysUser);
}
public SysUser selectUserByPhone(String phone) {
return userService.selectUserByPhone(phone);
}
/**
* 获取token
*
* @return
*/
public String getToken(LoginUser loginUser) {
return tokenService.createToken(loginUser);
}
public Authentication authenticate(Authentication authentication) {
return authenticationManager.authenticate(authentication);
}
}
b. 抽出原有密码登录为密码策略, 并继承抽出的公共类
密码这块跟原有的密码登录对比没有修改
package com.ruoyi.framework.handler;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
@Log4j2
@Component
public class PasswordLoginHanlder extends LoginHanlder implements LoginStrategy {
@Autowired
private ISysConfigService configService;
@Autowired
private RedisCache redisCache;
@Override
public String getLoginType() {
return "password";
}
@Override
public String login(String username, String password, String code, String uuid) {
log.info("这是密码策略");
boolean captchaEnabled = configService.selectCaptchaEnabled();
// 验证码开关
if (captchaEnabled) {
validateCaptcha(username, code, uuid);
}
// 用户验证
Authentication authentication = null;
try {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
AuthenticationContextHolder.setContext(authenticationToken);
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticate(authenticationToken);
} catch (Exception e) {
if (e instanceof BadCredentialsException) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
} else {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
} finally {
AuthenticationContextHolder.clearContext();
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
// 生成token
return getToken(loginUser);
}
/**
* 校验验证码
*
* @param username 用户名
* @param code 验证码
* @param uuid 唯一标识
* @return 结果
*/
private void validateCaptcha(String username, String code, String uuid) {
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey);
if (captcha == null) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
throw new CaptchaExpireException();
}
if (!code.equalsIgnoreCase(captcha)) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
}
}
c. 创建短信登录策略
重点是这里,checkCode方法进行自定义校验,然后根据当前是手机号登录还是什么登录查出用户信息,之后的代码就是跟密码登录一样了,不用改什么了
checkCode(phone, code);
log.info("这是短信登录");
//查询用户
SysUser sysUser = selectUserByPhone(phone);
附上完整代码
package com.ruoyi.framework.handler;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import java.util.List;
@Log4j2
@Component
public class SmsLoginHanlder extends LoginHanlder implements LoginStrategy {
@Autowired
private RedisCache redisCache;
@Override
public String getLoginType() {
return "sms";
}
@Override
public String login(String phone, String password, String code, String uuid) {
checkCode(phone, code);
log.info("这是短信登录");
//查询用户
SysUser sysUser = selectUserByPhone(phone);
if (ObjectUtil.isEmpty(sysUser)) {
throw new UserPasswordNotMatchException();
}
// 用户验证
Authentication authentication = null;
try {
authentication = authenticate(new LoginAuthenticationToken(sysUser.getUserName(), "sms"));
} catch (Exception e) {
if (e instanceof BadCredentialsException) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
} else {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
} finally {
AuthenticationContextHolder.clearContext();
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
// 生成token
return getToken(loginUser);
}
@SneakyThrows
private void checkCode(String phone, String code) {
if (StrUtil.isBlank(code)) {
throw new RuntimeException("验证码不能为空");
}
if (isSuperAccount(phone)) {
return;
}
String key = "SMS_CODE_KEY:" + phone;
redisCache.redisTemplate.setKeySerializer(new StringRedisSerializer());
if (!redisCache.redisTemplate.hasKey(key)) {
throw new RuntimeException("验证码不正确");
}
Object codeObj = redisCache.redisTemplate.opsForValue().get(key);
if (codeObj == null) {
throw new RuntimeException("验证码不正确");
}
String saveCode = codeObj.toString();
if (StrUtil.isBlank(saveCode)) {
redisCache.redisTemplate.delete(key);
throw new RuntimeException("验证码不正确");
}
if (!StrUtil.equals(saveCode, code)) {
throw new RuntimeException("验证码不正确");
}
redisCache.redisTemplate.delete(key);
}
private Boolean isSuperAccount(String mobile) {
List<String> accountList = redisCache.redisTemplate.opsForList().range("SUPER_ACCOUNT:", 0, -1);
if (accountList != null) {
for (String s : accountList) {
if (mobile.contains(s)) {
return true;
}
}
}
return false;
}
}
到此策略就完成了
下面是用户登录操作
1. 修改LoginBody,添加登录类型
位置:com.ruoyi.common.core.domain.model
/**
* 登录类型
*/
private String loginType;
2. 原登录接口改为策略登录(/login)
位置:com.ruoyi.web.controller.system;
/**
* 登录方法
*
* @param loginBody 登录信息
* @return 结果
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody) {
if (ObjectUtils.isEmpty(loginBody.getLoginType())) {
return AjaxResult.error("登录类型不能为空");
}
// 生成令牌
String token = loginContext.getHandler(loginBody.getLoginType())
.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid());
AjaxResult ajax = AjaxResult.success();
ajax.put(Constants.TOKEN, token);
return ajax;
}
到此,后端接口部分就完成了
前端修改 以手机号验证码为例
1. 修改src/api 下的login文件
修改
// 登录方法
export function login(username, password, code, uuid, loginType) {
const data = {
username,
password,
code,
uuid,
loginType
}
return request({
url: '/login',
headers: {
isToken: false
},
method: 'post',
data: data
})
}
获取短信验证码
// 获取短信验证码
export function getSms(query) {
return request({
url: '/user/sms',
method: 'get',
params: query
})
}
2. 创建短信登录页面smslogin.vue
位置:src/views/smslogin
<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="code">
<el-input
v-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">
<el-button
type="primary"
@click="getVerify"
style="width:100%;"
>
<span v-show="show">获取验证码</span>
<span v-show="!show" class="count">{{ count }} s</span>
</el-button>
</div>
</el-form-item>
<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>
<div style="float: left;" v-if="login">
<router-link class="link-type" :to="'/login'">密码登录</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright yizhi-w.com All Rights Reserved.</span>
<span>ICP主体备案号: 辽ICP备2022012082号</span>
</div>
</div>
</template>
<script>
import Cookies from 'js-cookie'
import { getSms } from '@/api/login'
export default {
name: 'Login',
data() {
return {
codeUrl: '',
loginForm: {
username: '',
code: ''
},
loginRules: {
username: [
{ required: true, trigger: 'blur', message: '请输入您的手机号' }
],
code: [
{ required: true, trigger: 'blur', message: '请输入验证码' }
]
},
loading: false,
login: true,
redirect: undefined,
show: true,
count: '', // 初始化次数
timer: null,
queryParams: {
phone: null
}
}
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
}
},
created() {
this.getCookie()
},
methods: {
getVerify() {
// 验证手机号
if (this.checkPhone() === false) {
return false
} else {
this.queryParams.phone = this.loginForm.username
getSms(this.queryParams).then(res => {
this.$message.success('验证码发送成功')
const TIME_COUNT = 60 //更改倒计时时间
if (!this.timer) {
this.count = TIME_COUNT
this.show = false
this.timer = setInterval(() => {
if (this.count > 0 && this.count <= TIME_COUNT) {
this.count--
} else {
this.show = true
clearInterval(this.timer) // 清除定时器
this.timer = null
}
}, 1000)
}
})
}
},
checkPhone() {
let phone = this.loginForm.username
if (!/^1[3456789]\d{9}$/.test(phone)) {
this.$message.error('请填写正确的手机号')
return false
}
},
getCookie() {
const username = Cookies.get('username')
const code = Cookies.get('code')
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
code: code === undefined ? this.loginForm.code : code,
loginType: 'sms'
}
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('Login', this.loginForm).then(() => {
this.$router.push({ path: this.redirect || '/' }).catch(() => {
})
}).catch(() => {
this.loading = false
})
}
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
</style>
3. 修改login.vue页面
位置:src/views/login
部分代码 放在相应位置,51行左右
<div style="float: left;" v-if="smslogin">
<router-link class="link-type" :to="'/smslogin'">短信登录</router-link>
</div>
loginForm添加 loginType: “password”,
loginForm: {
username: "admin",
password: "admin123",
rememberMe: false,
loginType: "password",
code: "",
uuid: ""
},
短信登录开关设置,放在了注册开关下面
// 注册开关
register: true,
smslogin: true,
getCookie方法添加 loginType: ‘password’
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),
loginType: 'password'
};
},
4. 修改登录相关,添加loginType
位置:src/store/modules/user.js
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim()
const password = userInfo.password
const code = userInfo.code
const uuid = userInfo.uuid
const loginType = userInfo.loginType
return new Promise((resolve, reject) => {
login(username, password, code, uuid, loginType).then(res => {
setToken(res.token)
commit('SET_TOKEN', res.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
5. 页面路由添加短信页面路由
位置:src/router/index.js
{
path: '/smslogin',
component: () => import('@/views/smslogin'),
hidden: true
},
6. 修改权限,添加个smslogin登录不鉴权
位置:src/permission.js
const whiteList = ['/login', '/auth-redirect', '/bind', '/register', '/smslogin']
到此后端、前端的登录都完成了
以后要添加其他登录,
后端只需添加新的策略,
前端根据需求相应新增,后台管理,小程序免密等