SpringBoot整合Redis(三 ) 将登录成功产生的token存入redis

通过SpringBoot整合Redis(二 ) springboot整合缓存redis 对redis有了初步的理解。接下来探索一下如何运用Redis存取、识别当前登录用户信息。

本次实现:

1.用户登录,校验用户名密码后,登录成功产生token值,保存入Redis中,设置时效50分钟。

2.使用拦截器/ SpringAop技术,当用户调用其他接口时,必须传入token值,并且比较token值是否有效(存在),是否正确。

约定 :

一个用户只能拥有一个token,用户重复登录时,也就是说用户登录的token还有效时,用户再次登录,此时token有效期重置。

存入Redis格式为 : adminId : token,当用户调用除登录接口外的其他接口(我这测试只考虑了两个接口),进行校验,先校验adminId是否存在,再校验token是否正确。

1.登录成功返回信息

SpringBoot整合Redis(三 ) 将登录成功产生的token存入redis_第1张图片

 2. 调用其他接口返回信息

SpringBoot整合Redis(三 ) 将登录成功产生的token存入redis_第2张图片

一、配置信息,依赖信息的配置

依赖信息和Redis、数据库连接的配置信息,上一篇博客中有 SpringBoot整合Redis(二 ) springboot整合缓存redis

二、数据库的设置

DROP TABLE IF EXISTS `jc_user`;
CREATE TABLE `jc_user` (
  `id` tinyint(11) NOT NULL,
  `user_name` varchar(150) NOT NULL COMMENT '用户名',
  `password` varchar(150) DEFAULT NULL,
  `user_age` tinyint(11) DEFAULT NULL COMMENT '用户年龄',
  `user_sex` tinyint(11) NOT NULL COMMENT '用户性别(1表示男、2表示女、3表示未知)',
  `city` varchar(150) NOT NULL,
  `deleted_flag` tinyint(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

三、代码实现

工具类

1. JSON / 对象转换类

package user.login.utils;

import java.util.List;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * JSON工具类
 *  将json和对象互相转换
 * @author wulongwei
 *
 */
public class JsonUtils {

	// 定义jackson对象

	private static final ObjectMapper MAPPER = new ObjectMapper();

	/**
	 * 将对象转换成json字符串。
	 * 
	 * @param data
	 * @return
	 */
	public static String objectToJson(Object data) {
		try {
			String string = MAPPER.writeValueAsString(data);
			return string;
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 将json结果集转化为对象
	 * 
	 * @param jsonData
	 * @param beanType
	 * @return
	 */
	public static  T jsonToPojo(String jsonData, Class beanType) {

		try {
			T t = MAPPER.readValue(jsonData, beanType);
			return t;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 将json数据转换成pojo对象list
	 * 
	 * @param jsonData
	 * @param beanType
	 * @return
	 */
	public static  List jsonToList(String jsonData, Class beanType) {

		JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
		try {
			List list = MAPPER.readValue(jsonData, javaType);
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

}

2.生成token类,登录成功后调用,如果同一用户重复登录,token的时效重置

package user.login.utils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
/**
 * 生产token,如果同一用户重复登录,token的时效重置
 * @author ASUS
 *
 */
@Service
public class ProductToken {

	/**
	 * 生成有时效的token
	 * 之后调其他接口需要校验adminId和token值
	 * @param key
	 * @param value
	 */
	public Map productToken(String key, String value) {
		Map infoMap = new HashMap();
		if(redisTemplate.opsForValue().get(key) == null) {
			//将登陆的信息保存如redis
			redisTemplate.opsForValue().set(key, value);
			infoMap.put(key, value);
		}
		//设置token有效的时间
		redisTemplate.expire(key, 3000, TimeUnit.SECONDS);
		return infoMap;
	}
	
	@Autowired
	private StringRedisTemplate redisTemplate;

}

接口响应类  (调用接口后用统一的格式进行返回)

package user.login.base;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

// 服务接口有响应  统一规范响应服务接口信息
@Data
@Slf4j
public class ResponseBase {

	private Integer rtnCode;
	private String msg;
	private Object data;

	public ResponseBase() {

	}

	public ResponseBase(Integer rtnCode, String msg, Object data) {
		super();
		this.rtnCode = rtnCode;
		this.msg = msg;
		this.data = data;
	}

	public static void main(String[] args) {
		ResponseBase responseBase = new ResponseBase();
		responseBase.setData("123456");
		responseBase.setMsg("success");
		responseBase.setRtnCode(200);
		System.out.println(responseBase.toString());
		log.info("wulongwei...");
	}

	@Override
	public String toString() {
		return "ResponseBase [rtnCode=" + rtnCode + ", msg=" + msg + ", data=" + data + "]";
	}

}
package user.login.base;

public class BaseApiService {

	public ResponseBase setResultError(Integer code, String msg) {
		return setResult(code, msg, null);
	}

	// 返回错误,可以传msg
	public ResponseBase setResultError(String msg) {
		return setResult(500, msg, null);
	}

	// 返回成功,可以传data值
	public ResponseBase setResultSuccess(Object data) {
		return setResult(200, "处理成功", data);
	}

	// 返回成功,沒有data值
	public ResponseBase setResultSuccess() {
		return setResult(200, "处理成功", null);
	}

	// 返回成功,沒有data值
	public ResponseBase setResultSuccess(String msg) {
		return setResult(200, msg, null);
	}

	// 通用封装
	public ResponseBase setResult(Integer code, String msg, Object data) {
		return new ResponseBase(code, msg, data);
	}
}

实体类

package user.login.entity;

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class User {

	private Integer userId;
	private String userName;
	private String password;
	private Integer userAge;
	private Short userSex;
	private String city;
}

拦截器:在每次调用接口时进行拦截,校验用户传递的adminId和token是否有效并且正确

package user.login.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import user.login.interceptor.UserInterceptor;


@Configuration  //适配器
public class WebMvcConfigurer extends WebMvcConfigurationSupport {

	@Bean
    public UserInterceptor getUserInterceptor() {
        return new UserInterceptor();
    }
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		/**
		 * 拦截器按照顺序执行
		 */
		registry.addInterceptor(getUserInterceptor()).excludePathPatterns("/user/login");
		super.addInterceptors(registry);
	}
}
package user.login.interceptor;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import user.login.base.ResponseBase;
import user.login.entity.dto.TokenInfo;
import user.login.utils.JsonUtils;

public class UserInterceptor implements HandlerInterceptor {

	@Autowired
	private StringRedisTemplate redisTemplate;

	/**
	 * 在请求处理之前进行调用(Controller方法调用之前)
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) {

		// 检查用户传递的 token是否合法
		TokenInfo tokenInfo = this.getUserToKen(request);
		if (StringUtils.isBlank(tokenInfo.getAdminId()) && StringUtils.isBlank(tokenInfo.getToken())) {
			// 返回登录
			System.out.println("没有传入对应的身份信息,返回登录");
			return false;
		}
		try {
			String token = redisTemplate.opsForValue().get(tokenInfo.getAdminId());
			if (token != null && token.equals(tokenInfo.getToken())) {
				System.out.println("校验成功");
				return true;
			} else {
				System.out.println("校验失败,返回登录");
				return false;
			}
		} catch (Exception e) {
			System.out.println("校验失败,对呀的信息匹配错误,返回登录");
			return false;
		}

	}

	/**
	 * 在cookie中获取用户传递的token
	 */
	private TokenInfo getUserToKen(HttpServletRequest request) {
		TokenInfo info = new TokenInfo();
		String adminId = request.getHeader("adminId");
		String token = request.getHeader("token");
		if (StringUtils.isNotBlank(adminId) && StringUtils.isNotBlank(token)) {
			info.setAdminId(adminId);
			info.setToken(token);
		}
		return info;
	}

	/**
	 * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView mv)
			throws Exception {

	}

	/**
	 * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行 (主要是用于进行资源清理工作)
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex)
			throws Exception {

	}

	public void returnErrorResponse(HttpServletResponse response, ResponseBase result)
			throws IOException, UnsupportedEncodingException {
		OutputStream out = null;
		try {
			response.setCharacterEncoding("utf-8");
			response.setContentType("text/json");
			out = response.getOutputStream();
			out.write(JsonUtils.objectToJson(result).getBytes("utf-8"));
			out.flush();
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

}

控制器层

package user.login.controller;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.demo.entity.UserDto;
import user.login.base.ResponseBase;
import user.login.service.UserService;

@RestController
@RequestMapping(value = "/user")
public class UserController {

	/**
	 * 登陆成功返回token给前台,之后每调一个接口都需要校验token之后有效
	 * @param username
	 * @param passwrod
	 * @return
	 */
	@PostMapping("/login")
	public ResponseBase UserLogin(@RequestBody @Valid UserDto userDto, HttpServletRequest request) {
		return userService.UserLogin(userDto.getUserName(), userDto.getPassword());
	}
	
	/**
	 * 查看用户的基本信息
	 * @param id
	 * @return
	 */
	@GetMapping("/getUserInfo")
	public ResponseBase getUserInfo(Integer id) {
		return userService.getUserInfo(id);
	}
	
	@Autowired
	private UserService userService;
}

service实现

package user.login.service.impl;

import java.util.Map;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redis.demo.entity.User;
import user.login.base.BaseApiService;
import user.login.base.ResponseBase;
import user.login.mapper.UserMapper;
import user.login.service.UserService;
import user.login.utils.ProductToken;

@Service
@Transactional
public class UserServiceImpl extends BaseApiService implements UserService{

	@Override
	public ResponseBase UserLogin(String username, String passwrod) {
		//1.校验登陆是否成功
		User user = userMapper.getUserInfo(username, passwrod);
		//2.如果不成功返回提示
		if (user == null) {
			return setResultError("账户名密码错误!!!");
		} else {
			//3.如果成功,生产一个token
			String token = UUID.randomUUID().toString().replaceAll("-", "");
			Map mapInfo = productToken.productToken(user.getId().toString(), token);
			//3.返回token信息(有效期50分钟)
			return setResultSuccess((Object)mapInfo);
		}
	}

	@Override
	public ResponseBase getUserInfo(Integer userId) {
		User user = userMapper.getUser(userId);
		if(user != null) {
			return setResultSuccess((Object)user);
		} else {
			return setResultSuccess("无此用户");
		}
	}
	
	@Autowired
	private ProductToken productToken;
	@Autowired
	private UserMapper userMapper;
	
}

mapper层

package user.login.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.SelectProvider;
import org.springframework.stereotype.Repository;
import redis.demo.entity.User;
import user.login.mapper.sql.UserSqlProvider;

@Repository
@Mapper
public interface UserMapper {

	/**
	 * 通过用户名、密码获取用户信息
	 * @param userName
	 * @param password
	 * @return
	 */
	@SelectProvider(method = "select", type = UserSqlProvider.class)
	@Results(id="user", value={
			@Result(column="id", property="userId", id=true),
		    @Result(column="user_name", property="userName"),
		    @Result(column="user_age", property="userAge"),
		    @Result(column="user_sex", property="userSex"),
		    @Result(column="city", property="city")
	})
	User getUserInfo(String userName, String password);
	
	/**
	 * 通过用户ID查询用户基本信息
	 * @param userId
	 * @return
	 */
	@SelectProvider(method = "selectById", type = UserSqlProvider.class)
	@ResultMap(value="user")
	User getUser(Integer userId);
}
package user.login.mapper.sql;

import org.apache.ibatis.jdbc.SQL;

public class UserSqlProvider {

	public String select(final String userName, final String password) {

		String sql = new SQL() {
			{
				SELECT("*");
				FROM("jc_user");
				WHERE("deleted_flag = false AND user_name='" + userName + "' AND password= '" + password + "'");
			}
		}.toString();
		return sql;
	}

	public String selectById(final Integer userId) {

		String sql = new SQL() {
			{
				SELECT("*");
				FROM("jc_user");
				WHERE("deleted_flag = false  AND id= '" + userId + "'");
			}
		}.toString();
		return sql;
	}

}

启动类

@SpringBootApplication
@MapperScan(basePackages= {"user.login.mapper"})
public class app {

	public static void main(String[] args) {
		SpringApplication.run(app.class, args);
	}
}

代码链接

链接:https://pan.baidu.com/s/1YQC5MwfR4q3ckVgm1epalg 
提取码:eagh 
 

你可能感兴趣的:(springBoot)