当前位置:   article > 正文

SpringBoot实现token认证(基于缓存)_springboot中token存储到hashmap中

springboot中token存储到hashmap中

一、序言

本博客基于SpringBoot,使用redis缓存实现token认证,来验证用户身份的合法性。

二、什么是token?

token意为令牌,为一个随机的字符串UUID生成,用来标记来访用户的身份,通过该token,可以得出是哪一个用户向我服务器访问资源。

三、验证流程

当用户登录成功之后,则向客户端发送token,用来标记该用户,以后每次用户向服务器访问时,则在请求头带上该token。服务器从请求头中获取token,拿到该token之后,向redis缓存查找是否存在此token,如存在,则返回给用户相应的资源,若不存在,则返回,不给与资源。

四、程序实现

1.引入Maven依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>1.5.21.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.chen</groupId>
  12. <artifactId>cachetest</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>cachetest</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  19. <java.version>1.8</java.version>
  20. </properties>
  21. <dependencies>
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter-jdbc</artifactId>
  25. </dependency>
  26. <dependency>
  27. <groupId>org.springframework.boot</groupId>
  28. <artifactId>spring-boot-starter-web</artifactId>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.mybatis.spring.boot</groupId>
  32. <artifactId>mybatis-spring-boot-starter</artifactId>
  33. <version>2.0.1</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-starter-cache</artifactId>
  38. </dependency>
  39. <dependency>
  40. <groupId>mysql</groupId>
  41. <artifactId>mysql-connector-java</artifactId>
  42. <scope>runtime</scope>
  43. </dependency>
  44. <dependency>
  45. <groupId>org.springframework.boot</groupId>
  46. <artifactId>spring-boot-starter-test</artifactId>
  47. <scope>test</scope>
  48. </dependency>
  49. <dependency>
  50. <groupId>junit</groupId>
  51. <artifactId>junit</artifactId>
  52. <version>4.12</version>
  53. <scope>test</scope>
  54. </dependency>
  55. <dependency>
  56. <groupId>org.springframework.boot</groupId>
  57. <artifactId>spring-boot-test</artifactId>
  58. <version>2.1.6.RELEASE</version>
  59. <scope>test</scope>
  60. </dependency>
  61. <!-- 配置使用redis启动器 -->
  62. <dependency>
  63. <groupId>org.springframework.boot</groupId>
  64. <artifactId>spring-boot-starter-data-redis</artifactId>
  65. </dependency>
  66. <!-- 集成lombok简化代码 -->
  67. <dependency>
  68. <groupId>org.projectlombok</groupId>
  69. <artifactId>lombok</artifactId>
  70. </dependency>
  71. <!--将对象转为json字符串-->
  72. <dependency>
  73. <groupId>org.json</groupId>
  74. <artifactId>json</artifactId>
  75. </dependency>
  76. <dependency>
  77. <groupId>commons-io</groupId>
  78. <artifactId>commons-io</artifactId>
  79. </dependency>
  80. </dependencies>
  81. <build>
  82. <plugins>
  83. <plugin>
  84. <groupId>org.springframework.boot</groupId>
  85. <artifactId>spring-boot-maven-plugin</artifactId>
  86. </plugin>
  87. </plugins>
  88. </build>
  89. </project>

2.创建user表

3.编写application.properties

  1. #配置数据源
  2. spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
  3. spring.datasource.username=root
  4. spring.datasource.password=123456
  5. #开启驼峰命名
  6. mybatis.configuration.map-underscore-to-camel-case=true
  7. #配置redis
  8. spring.redis.host=localhost
  9. spring.redis.port=6379
  10. #打印SQL语句日志
  11. logging.level.com.chen.mapper=debug

4.编写用户类User

  1. package com.chen.bean;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @AllArgsConstructor
  7. @NoArgsConstructor
  8. public class User {
  9. int id;
  10. String username;
  11. String password;
  12. }

5.编写Mapper

  1. package com.chen.mapper;
  2. import com.chen.bean.User;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import org.apache.ibatis.annotations.Select;
  5. @Mapper
  6. public interface UserMapper {
  7. @Select("SELECT * FROM `user` WHERE username=#{username} AND password=#{password}")
  8. public User getUser(User user);
  9. }

6.编写Service

  1. package com.chen.service;
  2. import com.chen.bean.User;
  3. import com.chen.mapper.UserMapper;
  4. import org.springframework.stereotype.Service;
  5. import javax.annotation.Resource;
  6. @Service
  7. public class UserService {
  8. @Resource
  9. private UserMapper userMapper;
  10. public User getUser(User user) {
  11. User u = userMapper.getUser(user);
  12. return u;
  13. }
  14. }

7.编写Msg类,用来封装返回的信息

  1. package com.chen.util;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. public class Msg {
  5. // 状态码: 200-成功 400-失败 500-异常
  6. private int status;
  7. // 提示信息
  8. private String message;
  9. // 用户返回给浏览器的数据
  10. private Map<String, Object> data = new HashMap<String, Object>();
  11. public static Msg success() {
  12. Msg result = new Msg();
  13. result.setStatus(200);
  14. result.setMessage("处理成功!");
  15. return result;
  16. }
  17. public static Msg fail() {
  18. Msg result = new Msg();
  19. result.setStatus(400);
  20. result.setMessage("处理失败!");
  21. return result;
  22. }
  23. public static Msg error() {
  24. Msg result = new Msg();
  25. result.setStatus(500);
  26. result.setMessage("未知异常!");
  27. return result;
  28. }
  29. public Msg add(String key, Object value) {
  30. this.data.put(key, value);
  31. return this;
  32. }
  33. public int getStatus() {
  34. return status;
  35. }
  36. public void setStatus(int status) {
  37. this.status = status;
  38. }
  39. public String getMessage() {
  40. return message;
  41. }
  42. public void setMessage(String message) {
  43. this.message = message;
  44. }
  45. public Map<String, Object> getData() {
  46. return data;
  47. }
  48. public void setData(Map<String, Object> data) {
  49. this.data = data;
  50. }
  51. }

8.编写Controller

  1. package com.chen.controller;
  2. import com.chen.bean.User;
  3. import com.chen.service.UserService;
  4. import com.chen.util.Msg;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.data.redis.core.StringRedisTemplate;
  7. import org.springframework.stereotype.Controller;
  8. import org.springframework.web.bind.annotation.PostMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. import java.util.UUID;
  11. import java.util.concurrent.TimeUnit;
  12. @RestController
  13. public class UserController {
  14. @Autowired
  15. private StringRedisTemplate stringRedisTemplate;
  16. @Autowired
  17. private UserService userService;
  18. @PostMapping("/login")
  19. public Msg login(User user) {
  20. User u = userService.getUser(user);
  21. if (u != null) {
  22. String token = UUID.randomUUID().toString().replaceAll("-", "");
  23. stringRedisTemplate.opsForValue().set(token, String.valueOf(u.getId()), 3600, TimeUnit.SECONDS);//将用户的ID信息存入redis缓存,并设置一小时的过期时间
  24. return Msg.success().add("token",token).add("info","登录成功");
  25. }else {
  26. return Msg.fail().add("info", "登录失败");
  27. }
  28. }
  29. @PostMapping("/other")
  30. public Msg other() {
  31. return Msg.success().add("info", "该接口是来测试的");
  32. }
  33. }

9.配置启动类,使mapper生效

  1. package com.chen;
  2. import org.mybatis.spring.annotation.MapperScan;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.cache.annotation.EnableCaching;
  6. @MapperScan("com.chen.mapper")
  7. @SpringBootApplication
  8. @EnableCaching
  9. public class CachetestApplication {
  10. public static void main(String[] args) {
  11. SpringApplication.run(CachetestApplication.class, args);
  12. }
  13. }

10.设置拦截器,在进行接口访问前,先验证token的正确性

  1. package com.chen.interceptor;
  2. import com.chen.util.Msg;
  3. import org.json.JSONObject;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.data.redis.core.StringRedisTemplate;
  7. import org.springframework.stereotype.Component;
  8. import org.springframework.web.servlet.HandlerInterceptor;
  9. import org.springframework.web.servlet.ModelAndView;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;
  12. import java.io.IOException;
  13. import java.io.PrintWriter;
  14. @Component
  15. public class ParamInterceptor implements HandlerInterceptor {
  16. @Autowired
  17. private StringRedisTemplate stringRedisTemplate;
  18. @Override
  19. public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
  20. String token = httpServletRequest.getHeader("token");
  21. //token验证
  22. if(token!=null){
  23. String id = stringRedisTemplate.opsForValue().get(token);
  24. if(id!=null){
  25. System.out.println("token验证成功");
  26. return true;
  27. }else{
  28. System.out.println("token验证失败");
  29. returnJson(httpServletResponse);
  30. return false;
  31. }
  32. }else{
  33. System.out.println("token验证失败");
  34. returnJson(httpServletResponse);
  35. return false;
  36. }
  37. }
  38. private void returnJson(HttpServletResponse response){
  39. PrintWriter writer = null;
  40. response.setCharacterEncoding("UTF-8");
  41. response.setContentType("application/json; charset=utf-8");
  42. try {
  43. writer = response.getWriter();
  44. Msg msg = Msg.fail().add("info", "没有token或token无效");
  45. JSONObject jsonObject = new JSONObject(msg);
  46. writer.print(jsonObject);
  47. } catch (IOException e){
  48. e.printStackTrace();
  49. } finally {
  50. if(writer != null){
  51. writer.close();
  52. }
  53. }
  54. }
  55. @Override
  56. public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
  57. }
  58. @Override
  59. public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
  60. }
  61. }

11.配置拦截器,使前一步设置的拦截器生效

  1. package com.chen.config;
  2. import com.chen.interceptor.ParamInterceptor;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  6. import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
  7. @Configuration
  8. public class InterceptorConfig extends WebMvcConfigurationSupport {
  9. @Autowired
  10. private ParamInterceptor paramInterceptor;
  11. public void addInterceptors(InterceptorRegistry registry) {
  12. //此处配置拦截路径
  13. registry.addInterceptor(paramInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
  14. }
  15. }

登录之后的结果:

 使用其他接口进行测试:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/368070
推荐阅读
相关标签
  

闽ICP备14008679号