当前位置:网站首页>2. Login - verification code function and saving login status

2. Login - verification code function and saving login status

2022-07-26 02:09:00 A snicker

In the login interface , It mainly realizes two functions , Refresh the verification code and remember my function
 Insert picture description here

Verification Code

Generate captcha

Use kaptcha Generate verification code , Import jar package , Write corresponding config Configuration class , And then in controller Generate verification code in . newly build cookie, stay cookie Put the verification code in uuid, take cookie As key Deposit in redis, hold text As value, Add expiration time on .
adopt response.addCookie(cookie) hold cookie Send to front end ,OutputStream os = response.getOutputStream(); ImageIO.write(image,“png”,os); Output the picture to the browser .

@GetMapping("/kaptcha")
    public void getKaptcha(HttpServletResponse response){
    
        //  Generate verification code 
        String text = kaptchaProducer.createText();
        BufferedImage image = kaptchaProducer.createImage(text);

        //  Verification code attribution 
        String kaptchaOwner = CommunityUtil.generateUUID();
        Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
        cookie.setMaxAge(60);
        cookie.setPath(contextPath);
        response.addCookie(cookie);

        //  Deposit in Redis
        String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
        redisTemplate.opsForValue().set(redisKey,text,60, TimeUnit.SECONDS);

        //  Output image to browser 
        try{
    
            OutputStream os = response.getOutputStream();
            ImageIO.write(image,"png",os);
        } catch (IOException e) {
    
            LOGGER.error(" Response verification code failed :" + e.getMessage());
        }
    }
Verification code
// @CookieValue("kaptchaOwner") String kaptchaOwner

String kaptcha = null;
// cookie Not empty , adopt redis Of key obtain value
if(StringUtils.isNoneBlank(kaptchaOwner)){
    
    String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
    kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
}
//  Verification code error, etc 
if(StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)){
    
    model.addAttribute("codeMsg"," The verification code is incorrect !");
    return "site/login";
}

Save login status

Timeout of login credentials in the default state 12 Hours , Remember the login credential timeout in status 100 God .

service layer :

//  Generate login credentials 
LoginTicket loginTicket = new LoginTicket();
loginTicket.setUserId(user.getId());
loginTicket.setTicket(CommunityUtil.generateUUID());
loginTicket.setStatus(0);
loginTicket.setExpired(new Date(System.currentTimeMillis() + expiredSeconds * 1000));

String redisKey = RedisKeyUtil.getTicketKey(loginTicket.getTicket());
// loginTicket Will be serialized as json
redisTemplate.opsForValue().set(redisKey, loginTicket);

map.put("ticket", loginTicket.getTicket());
return map;

controller layer :

//  Do you remember me 
int expiredSeconds = rememberme ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;

Map<String, Object> map = userService.login(username, password, expiredSeconds);
String key = "ticket";
if(map.containsKey(key)){
    
	//  newly build cookie, To configure cookie
    Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
    cookie.setPath(contextPath);
    cookie.setMaxAge(expiredSeconds);
    response.addCookie(cookie);
    return "redirect:/";
} else{
    
	//  Return error message 
    model.addAttribute("usernameMsg",map.get("usernameMsg"));
    model.addAttribute("passwordMsg",map.get("passwordMsg"));
    return "site/login";
}

Automatic login implementation

First encapsulate two gadget classes
From you to cookie Get in the ticket Value , First package one cookieUtil:

public class CookieUtil {
    
    public static String getValue(HttpServletRequest request, String name) {
    
        if (request == null || name == null) {
    
            throw new IllegalArgumentException(" The parameter is empty. !");
        }
        Cookie[] cookies = request.getCookies();
        //  Traverse cookie, Find the one we want 
        if (cookies != null) {
    
            for (Cookie cookie : cookies) {
    
                if (cookie.getName().equals(name)) {
    
                    return cookie.getValue();
                }
            }
        }
        return null;
    }
}

The browser processes multiple user requests at the same time , For each user user Objects need to be stored , have access to session, however session rely on servlet api, We want to use and take in the method , To solve this problem , We need to adopt a new method to store user information ——ThreadLocal.

ThreadLocal, seeing the name of a thing one thinks of its function , Is the local thread , But this name is easy to misunderstand , Because it actually means local variables of local threads , First we need to know , Each request corresponds to a thread , This ThreadLocal It is a variable in the process of using this thread , This variable is owned by its thread , Each thread does not affect each other .

We encapsulate a tool HostHolder, Used to hold user information , Instead of session object . There are mainly add query and delete methods , Make multi-user login conflict free .

@Component
public class HostHolder {
    

    private ThreadLocal<User> users = new ThreadLocal<>();

    public void setUser(User user) {
    
        users.set(user);
    }

    public User getUser() {
    
        return users.get();
    }

    public void clear() {
    
        users.remove();
    }
}

Rewrite first preHandler Method , Use the front package cookieUtil Tools get ticket, Find out the user , And use hostHolder Hold users .

@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    
        //  from cookie Get vouchers from 
        String ticket = CookieUtil.getValue(request, "ticket");
        if (ticket != null) {
    
            //  Query voucher 
            LoginTicket loginTicket = userService.findLoginTicket(ticket);
            //  Check whether the voucher is valid 
            if (loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())) {
    
                //  Query user according to voucher 
                User user = userService.findUserById(loginTicket.getUserId());
                //  Hold user... In this request 
                hostHolder.setUser(user);
                //  Build the results of user authentication , And deposit in SecurityContext, In order to Security To authorize 
                Authentication authentication =
                        new UsernamePasswordAuthenticationToken(
                                user, user.getPassword(), userService.getAuthorities(user.getId())
                        );
                SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
            }
        }
        return true;
    }
Display user data on the template view

Then rewrite postHandle Method , stay modelAndView Add up user.

@Override
public void postHandle(
        HttpServletRequest request,
        HttpServletResponse response,
        Object handler,
        ModelAndView modelAndView) throws Exception {
    
    User user = hostHolder.getUser();
    if (user != null && modelAndView != null) {
    
        modelAndView.addObject("loginUser", user);
    }
}
Clean up user data at the end of the request
@Override
public void afterCompletion(
        HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    hostHolder.clear();
}
原网站

版权声明
本文为[A snicker]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/201/202207190127380015.html