实现思路
- 用户在未登录状态下通过路径访问项目,显示未登录
- 用户通过账号密码登录后,返回token值
- 登录后,可以通过路径访问项目
- 没有在Headers中添加token时,无法注销;添加了token后,可以成功注销用户
项目结构
添加redis依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>com.example.demo.DemoApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
配置redis信息和服务器端口号
server:
port: 8083
spring:
redis:
host: localhost
port: 6379
database: 5
实现redis操作代码:添加、获取、删除
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
@Service
public class RedisService {
@Autowired
RedisTemplate redisTemplate;
public void set(String key,Object value){
//更改在redis里面查看key编码问题
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
ValueOperations<String,Object> vo = redisTemplate.opsForValue();
vo.set(key,value);
}
public Object get(String key){
ValueOperations<String,Object> vo = redisTemplate.opsForValue();
return vo.get(key);
}
public boolean delete(String key){
return redisTemplate.delete(key);
}
}
实现登录和注销功能代码
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
@Service
public class LoginService {
@Autowired
RedisService redisService;
/**
* 进行登录操作,如果用户名和密码正确,使用UUID一个字符串作为token
* @param username
* @param password
* @return
*/
public String login(String username,String password){
if(username.equals("liu")&&password.equals("123")){
String token = UUID.randomUUID().toString();
redisService.set(token,username);
return username+"登录成功,token是:"+token;
}else {
return "用户名或密码错误";
}
}
/**
* 进行注销操作,实质是删除redis和token中的缓存
* @param httpServletRequest
* @return
*/
public String logout(HttpServletRequest httpServletRequest){
String token = httpServletRequest.getHeader("token");
boolean delete = redisService.delete(token);
if (delete){
return "注销成功";
}else {
return "注销失败";
}
}
}
针对登录和注销功能实现Controller方便后面调用
package com.example.demo.controller;
import com.example.demo.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* 在controller中对登录和注销方法进行调用
*/
@RestController
@RequestMapping("/login")
public class LoginController {
@Autowired
LoginService loginService;
@RequestMapping("/login")
public String login(String username, String password) {
return loginService.login(username, password);
}
@RequestMapping("/logout")
public String logout(HttpServletRequest httpServletRequest) {
return loginService.logout(httpServletRequest);
}
}
再写一个测试的Controller类,用来测试用户没登录的时候,通过路径无法访问
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping("test")
public String test(){
return "test";
}
}
实现一个拦截器,对用户登录状态进行判断
package com.example.demo.interceptor;
import com.example.demo.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
/**
* 拦截器中需要取出header中的token,然后去redis中进行判断,如果存在,则允许操作,则返回提示信息
*/
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
RedisService redisService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
response.getWriter().print("用户未登录");
return false;
}
Object loginStatues = redisService.get(token);
if (Objects.isNull(loginStatues)) {
response.getWriter().print("token错误");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
配置拦截器
package com.example.demo.config;
import com.example.demo.interceptor.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AuthConfig implements WebMvcConfigurer {
@Autowired
AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor).addPathPatterns("/test/**").excludePathPatterns("/login/**");
}
}
源码
https://github.com/Wranglery/springboot_redis_token_login/tree/main/springboot_redis_token_login