I Twice MD5 encryption
①. Purpose of MD5 encryption
Purpose of MD5 encryption
- If nothing is done, the plaintext password will be transmitted on the network. If the data is obtained by a malicious user in the transmission process, the password can be obtained, so it is not safe
②. The purpose of MD5 encryption twice
The purpose of MD5 encryption twice
- The purpose of the second encryption is to prevent the database from being invaded and the password is found out by people through the rainbow table. Therefore, after the server receives the password, it does not write it directly to the database, but generates a random salt, and then stores it in the database after MD5 encryption
③. Realize MD5 twice encryption function
package com.xizi.miaosha.util; import org.apache.commons.codec.digest.DigestUtils; /** * @author xizizzz * @description: Twice md5 encryption algorithm * @date 2021-6-23 07:48 PM */ public class EncyptionUtil { //Import md5 encryption algorithm into commons codec package public static String md5(String str) { return DigestUtils.md5Hex(str); } //md5 encryption + salt public static String md5WithSalt(String pwd, String salt) { //Take the characters at the position of string 0 2 5 4 and splice them into a new string String str = "" + salt.charAt(0) + salt.charAt(2) + pwd + salt.charAt(5) + salt.charAt(4); return md5(str); } public static void main(String[] args) { System.out.println(md5WithSalt("123456", "1a2b3c4d")); System.out.println(md5WithSalt(md5WithSalt("123456", "1a2b3c4d"), "1a2b3c4d")); } }
II Implementation of distributed Session
①. Problems arising
Problems arising
- The second kill service is actually distributed multiple servers. At this time, if the user logs in to the first server, the first request goes to the first server, but the second request goes to the second server, the user's session information will be lost.
②. Solution
Solution
- Implementation idea: after the user logs in successfully, generate a sessionid for the user (identify the user with a token), write it to the cookie and pass it to the client; Then, in subsequent access, the client passes the token in the cookie. After the server obtains the token, it obtains the corresponding session information according to the token (the token is generated by uuid)
③. Threadlocal stores the User object
// Threadlocal storage user will not affect the object. Each time a request comes in, it will generate its own thread variable to store public class UserContext { //ThreadLocal is used to access user information. One thread saves one user information private static ThreadLocal<User> userHolder = new ThreadLocal<User>(); //obtain public static void setUser(User user) { userHolder.set(user); } //set up public static User getUser() { return userHolder.get(); } }
④. The login function creates a token and stores it in Redis and cookies
Business code of login function
// Login implementation public ResultEnum login(LoginVO loginVO, HttpServletResponse response) { log.info("[[login authentication] user information:{}", loginVO.toString()); if (loginVO == null) { // Throw parameter error throw new CustomException(ResultEnum.PARAM_ERROR); } String mobile = loginVO.getMobile(); //TKMybatis internal method implementation direct call User user = userMapper.selectByPrimaryKey(mobile); if (user == null) { // Thrown user does not exist throw new CustomException(ResultEnum.USER_NOT_EXIST); } //Get salt value String salt = user.getSalt(); //Call the tool class to md5 encrypt twice for password comparison String loginPwd = EncyptionUtil.md5WithSalt(loginVO.getPassword(), salt); if (!loginPwd.equals(user.getPassword())) { //Throw password error throw new CustomException(ResultEnum.PASSWORD_ERROR); } //Set user to ThreadLocalh UserContext.setUser(user); // Login is successful. Call UUID tool class to generate token String token = UUIDUtil.getUUID(); //Store the token in the cookie, and store the user information and token in redis addUpdateSession(response, token, user); //Return login success enumeration class properties return ResultEnum.LOGIN_SUCCESS; }
The session is added for the first visit, and the session is updated for subsequent visits
// The session is added for the first access, and the session is updated for subsequent access (updating is to regenerate the session to maintain the lifetime of the session) private void addUpdateSession(HttpServletResponse response, String token, User user) { //Create a cookie object Cookie cookie = new Cookie(CookieProperties.COOKIE_NAME, token); //Set the expiration time of the cookie cookie.setMaxAge(UserPrefix.getByCookie.getExpireSeconds()); cookie.setPath("/"); response.addCookie(cookie); // Store the token and user information in redis redisService.set(UserPrefix.getByCookie, token, user); }
⑤. Configure the automatic binding of User information to the Controller layer interface every time a request is made
Its function is to parse the User parameter of request request and automatically bind the data to the input parameter of Controller
package com.xizi.miaosha.config; /** * @author xizizzz * @description: Its function is to parse the request parameters and bind the data to the input parameters of the Controller * @date 2021-6-23 07:48 PM */ // To customize a parameter parser, you need to implement the HandlerMethodArgumentResolver interface, // Override the supportsParameter and resolveArgument methods, and add the resolver configuration to the configuration file. @Component public class UserArgumentResolver implements HandlerMethodArgumentResolver { @Autowired private UserService userService; //Returns the User object type @Override public boolean supportsParameter(MethodParameter methodParameter) { Class<?> clazz = methodParameter.getParameterType(); return (clazz == User.class); } @Override public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception { //Returns the user stored in ThreadLocal return UserContext.getUser(); } }