用户登录流程以及代码实现

后端
@Override
public Result login(ConsumeUser consumeUser) {
ConsumeUser consumeUser1 = query().eq("account",consumeUser.getAccount()).eq("password",consumeUser.getPassword()).one();
if (consumeUser1 != null) {
String token = UUID.randomUUID().toString();
UserDTO userDTO = BeanUtil.copyProperties(consumeUser1, UserDTO.class);
Map<String, Object> map=BeanUtil.beanToMap(userDTO,new HashMap<>(), CopyOptions.create()
.setIgnoreNullValue(true)
.setFieldValueEditor((filedName,filedValue)->filedValue.toString())
);
redisTemplate.opsForHash().putAll(LOGIN_USER_KEY+token,map);
redisTemplate.expire(LOGIN_USER_KEY+token,LOGIN_USER_TTL, TimeUnit.MINUTES);
return Result.success(token);
}
return Result.error("未找到用户");
}
package com.example.consumeserver.util;
import com.example.consumeserver.dto.UserDTO;
public class UserHolder {
private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
public static void saveUser(UserDTO user){
tl.set(user);
}
public static UserDTO getUser(){
return tl.get();
}
public static void removeUser(){
tl.remove();
}
}
登录拦截器
package com.example.consumeserver.util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import io.netty.util.internal.StringUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(UserHolder.getUser() == null){
response.setStatus(401);
return false;
}
return true;
}
}
刷新token拦截器
package com.example.consumeserver.interceptor;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.example.consumeserver.dto.UserDTO;
import com.example.consumeserver.util.RedisConstants;
import com.example.consumeserver.util.UserHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.example.consumeserver.util.RedisConstants.LOGIN_USER_KEY;
public class RefreshTokenInterceptor implements HandlerInterceptor {
private StringRedisTemplate stringRedisTemplate;
public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token=request.getHeader("authorization");
if(StrUtil.isBlank(token)){
return true;
}
String key=LOGIN_USER_KEY + token;
Map<Object, Object> user = stringRedisTemplate.opsForHash().entries(key);
if(user.isEmpty()){
return true;
}
UserDTO userDTO = BeanUtil.fillBeanWithMap(user, new UserDTO(), false);
UserHolder.saveUser(userDTO);
stringRedisTemplate.expire(key, RedisConstants.LOGIN_USER_TTL, TimeUnit.SECONDS);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
配置文件
package com.example.consumeserver.config;
import com.example.consumeserver.util.LoginInterceptor;
import com.example.consumeserver.interceptor.RefreshTokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/login/**"
).order(1);
registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).order(0);
}
}
前端实现
<template>
<div>
<el-form ref="form" :model="consumeUser" label-width="80px">
<el-form-item label="账号">
<el-input v-model="consumeUser.account"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="consumeUser.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">登录</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
consumeUser: {
account: '',
password: ''
},
}
},
methods: {
onSubmit() {
axios.post('/api/login', this.consumeUser).then(res => {
const data = res.data;
if (data.code == 0) {
alert(data.msg)
return;
}
this.$message.success("登录成功");
sessionStorage.setItem("token", data.data);
this.$router.push('/menu')
}).catch(err =>{
console.log(err)
})
}
}
}
</script>
登录成功后界面
<template>
<div>
<el-container style="height:auto; border: 1px solid #eee">
<el-aside width="250px" style=" border: 1px solid #d4b6db">
<el-menu :router="true" :default-active="defaultActive" background-color="#545c64" text-color="#fff"
active-text-color="#ffd04b" :active-class="activeClass">
<el-submenu index="1">
<template slot="title"><i class="el-icon-star-on"></i><span>账单管理</span></template>
<el-menu-item index="/bill">账单一览</el-menu-item>
</el-submenu>
<el-submenu index="2">
<template slot="title"><i class="el-icon-platform-eleme"></i><span>个人信息管理</span></template>
<el-menu-item index="/user">个人信息</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-container>
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)">
<div>
消费通
<div style="float: right;">
<img v-if="user.url" :src="user.url" alt="User Avatar" class="user-avatar"
style="max-width: 30px; max-height: 30px;" />
<span v-if="user.name" style="margin-left: 10px;font-size: 30px">{{ user.name }}</span>
<span v-else>Loading...</span>
</div>
</div>
</el-header>
<el-main>
<div>
<router-view />
</div>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
activeClass: 'router-link-active',
defaultActive: '/bill',
submenuOpen: '1',
user: {
userId: '',
name: '',
url: ''
}
}
},
methods: {
},
created() {
let token = sessionStorage.getItem("token");
axios.interceptors.request.use(
config => {
if (token) {
config.headers['authorization'] = token
} else {
this.$message.error('登录失效,请重新登录')
this.$router.push('/login') // 使用 Vue Router 跳转
}
return config
},
error => {
console.log(error)
if (error.response && error.response.status === 401) {
this.$router.push('/login');
}
}
)
axios.get('/api/user/me').then(res => {
this.user = res.data.data;
}).catch(err => {
console.log(err);
})
},
}
</script>
<style>
.el-header,
.el-footer {
background-color: #B3C0D1;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #D3DCE6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #E9EEF3;
color: #333;
text-align: center;
line-height: 160px;
}
body>.el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
a {
text-decoration: none;
color: #333;
/* 默认颜色 */
}
/* 鼠标悬停时的样式 */
a:hover {
color: #ff0000;
/* 悬停时的颜色 */
}
/* 点击后的样式 */
a:active {
color: #00ff00;
/* 点击后的颜色 */
}
.router-link-active {
text-decoration: none;
color: #ffd04b;
}
</style>

浙公网安备 33010602011771号