下面是 "SpringBoot+Vue+Redis实现单点登录(一处登录另一处退出登录)" 的完整攻略。
一、前置知识
在讲解实现单点登录的过程中,我们需要掌握以下技术:
- SpringBoot:后端框架,用来提供 RESTful API 服务;
- Vue:前端框架,用来构建单页应用;
- Redis:一个内存数据库,用来保存用户会话信息。
如果对这些技术还不太了解,可以先学习相关的基础知识,再来实践本文的内容。
二、实现思路
单点登录(Single Sign-On)是一种让用户只要登录一次就可以在多个应用中享受无需重复登录的服务。本文实现的单点登录方案,基于 Token 的方式实现,如果用户在一处登录,则可以在其他处直接使用该 Token,而不需要再次输入用户名和密码。当用户在其中一处退出登录时,其他已登录的站点也会失效。
实现该方案的关键点在于 Token 的生成和获取,以及 Token 的存储和验证。下面我们将针对这些点逐一进行讲解。
三、Token 的生成和获取
我们采用 JWT(JSON Web Token)颁发 Token,具体实现过程:
- 用户在登录成功后,后端服务器使用 JWT 生成 Token,并返回给前端;
- 前端将 Token 保存在 localStorage 中;
- 前端携带 Token 向后端请求 API。
当用户在其他页面打开站点时,可以通过读取 localStorage 中保存的 Token,自动向后端请求 API,实现直接登录。
四、Token 的存储和验证
Token 的存储我们使用 Redis,将 Token 以键值对的形式存储在 Redis 中,Key 为 Token 的值,Value 为对应的 user_id。
Token 的验证我们可以利用 SpringBoot 的拦截器,在请求进入后台服务之后,使用 Redis 查询该 Token 对应的 user_id 是否存在,如果存在,则允许请求,如果不存在,则返回未登录状态。
五、示例说明
下面我们来看两个示例,分别说明 Token 的生成和存储,以及 Token 的验证。
1. Token 的生成和存储
后端代码
- 引入 JWT 库和 Redis 库。
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 登录生成 Token。
@PostMapping("/login")
public ResponseEntity login(@RequestBody User user) {
// 校验用户名和密码,生成token
String token = Jwts.builder()
.setSubject(user.getUserId())
.setExpiration(new Date(System.currentTimeMillis() + refreshTokenExpTime))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
// 存储到redis中
redisTemplate.opsForValue().set(token, user.getUserId(), refreshTokenExpTime, TimeUnit.MILLISECONDS);
return ResponseEntity.ok(new Auth(token, refreshTokenExpTime));
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Auth {
private String token;
private Long expireTime;
}
前端代码
- 登录成功后存储 Token。
export function login(username, password) {
return request({
url: '/login',
method: 'post',
data: {
username,
password
}
}).then(response => {
const {token, expireTime} = response.data;
localStorage.setItem('token', token);
localStorage.setItem('expireTime', expireTime);
return Promise.resolve(response.data);
});
}
2. Token 的验证
后端代码
- 配置 JwtTokenInterceptor 拦截器。
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Autowired
private JwtTokenInterceptor jwtTokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtTokenInterceptor)
.excludePathPatterns("/login", "/error", "/static/**");
}
}
- 编写 JwtTokenInterceptor 拦截器验证 Token 有效性。
public class JwtTokenInterceptor extends HandlerInterceptorAdapter {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
// 从redis缓存中查找该key
String userId = redisTemplate.opsForValue().get(token);
if (userId == null) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
// 将该user_id和token放入threadLocal中,方便后续使用
UserInfoHolder.setUserId(userId);
UserInfoHolder.setToken(token);
return true;
}
}
前端代码
对于前端来说,我们只需要在请求头中加上 Token 即可。
import axios from 'axios';
import router from '../router';
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 5000
});
service.interceptors.request.use(
config => {
if (localStorage.getItem('token')) {
// 如果 Token 存在,则在请求头中加入
config.headers.Authorization = localStorage.getItem('token');
}
return config;
},
error => {
return Promise.reject(error);
}
);
service.interceptors.response.use(
response => {
return response;
},
error => {
// 如果请求返回的状态码为 401,表示未经授权,则跳转到登录页
if (error.response.status === 401) {
router.push('/login');
}
return Promise.reject(error)
}
);
export default service;
以上就是实现单点登录方案的完整攻略,通过 Token 的存储和验证,我们可以在多个应用中实现单点登录的功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot+Vue+Redis实现单点登录(一处登录另一处退出登录) - Python技术站