springboot結合redis使用token實現登入登出功能
阿新 • • 發佈:2021-06-16
實現思路
- 使用者在未登入狀態下通過路徑訪問專案,顯示未登入
- 使用者通過賬號密碼登入後,返回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/**");
}
}