324 lines
12 KiB
Java
324 lines
12 KiB
Java
package com.greate.community.controller;
|
||
|
||
import com.google.code.kaptcha.Producer;
|
||
import com.greate.community.entity.User;
|
||
import com.greate.community.service.UserService;
|
||
import com.greate.community.util.CommunityConstant;
|
||
import com.greate.community.util.CommunityUtil;
|
||
import com.greate.community.util.RedisKeyUtil;
|
||
import org.apache.commons.lang3.StringUtils;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.beans.factory.annotation.Value;
|
||
import org.springframework.data.redis.core.RedisTemplate;
|
||
import org.springframework.security.core.context.SecurityContextHolder;
|
||
import org.springframework.stereotype.Controller;
|
||
import org.springframework.ui.Model;
|
||
import org.springframework.web.bind.annotation.*;
|
||
import javax.imageio.ImageIO;
|
||
import javax.servlet.ServletOutputStream;
|
||
import javax.servlet.http.Cookie;
|
||
import javax.servlet.http.HttpServletResponse;
|
||
import java.awt.image.BufferedImage;
|
||
import java.io.IOException;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
import java.util.concurrent.TimeUnit;
|
||
|
||
/**
|
||
* 登录、登出、注册
|
||
*/
|
||
@Controller
|
||
public class LoginController implements CommunityConstant {
|
||
|
||
private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
|
||
|
||
@Autowired
|
||
private UserService userService;
|
||
|
||
@Autowired
|
||
private Producer kaptchaProducer;
|
||
|
||
@Autowired
|
||
private RedisTemplate redisTemplate;
|
||
|
||
@Value("${server.servlet.context-path}")
|
||
private String contextPath;
|
||
|
||
/**
|
||
* 进入注册界面
|
||
* @return
|
||
*/
|
||
@GetMapping("/register")
|
||
public String getRegisterPage() {
|
||
return "site/register";
|
||
}
|
||
|
||
/**
|
||
* 进入登录界面
|
||
* @return
|
||
*/
|
||
@GetMapping("/login")
|
||
public String getLoginPage() {
|
||
return "site/login";
|
||
}
|
||
|
||
/**
|
||
* 进入重置密码界面
|
||
*/
|
||
@GetMapping("/resetPwd")
|
||
public String getResetPwdPage() {
|
||
return "site/reset-pwd";
|
||
}
|
||
|
||
/**
|
||
* 注册用户
|
||
* @param model
|
||
* @param user
|
||
* @return
|
||
*/
|
||
@PostMapping("/register")
|
||
public String register(Model model, User user) {
|
||
Map<String, Object> map = userService.register(user);
|
||
if (map == null || map.isEmpty()) {
|
||
model.addAttribute("msg", "注册成功, 我们已经向您的邮箱发送了一封激活邮件,请尽快激活!");
|
||
model.addAttribute("target", "/index");
|
||
return "/site/operate-result";
|
||
} else {
|
||
model.addAttribute("usernameMsg", map.get("usernameMsg"));
|
||
model.addAttribute("passwordMsg", map.get("passwordMsg"));
|
||
model.addAttribute("emailMsg", map.get("emailMsg"));
|
||
return "/site/register";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 激活用户
|
||
* @param model
|
||
* @param userId
|
||
* @param code 激活码
|
||
* @return
|
||
* http://localhost:8080/echo/activation/用户id/激活码
|
||
*/
|
||
@GetMapping("/activation/{userId}/{code}")
|
||
public String activation(Model model, @PathVariable("userId") int userId,
|
||
@PathVariable("code") String code) {
|
||
int result = userService.activation(userId, code);
|
||
if (result == ACTIVATION_SUCCESS) {
|
||
model.addAttribute("msg", "激活成功, 您的账号已经可以正常使用!");
|
||
model.addAttribute("target", "/login");
|
||
}
|
||
else if (result == ACTIVATION_REPEAT) {
|
||
model.addAttribute("msg", "无效的操作, 您的账号已被激活过!");
|
||
model.addAttribute("target", "/index");
|
||
}
|
||
else {
|
||
model.addAttribute("msg", "激活失败, 您提供的激活码不正确!");
|
||
model.addAttribute("target", "/index");
|
||
}
|
||
return "/site/operate-result";
|
||
}
|
||
|
||
|
||
/**
|
||
* 生成验证码, 并存入 Redis
|
||
* @param response
|
||
*/
|
||
@GetMapping("/kaptcha")
|
||
public void getKaptcha(HttpServletResponse response) {
|
||
// 生成验证码
|
||
String text = kaptchaProducer.createText(); // 生成随机字符
|
||
System.out.println("验证码:" + text);
|
||
BufferedImage image = kaptchaProducer.createImage(text); // 生成图片
|
||
|
||
// 验证码的归属者
|
||
String kaptchaOwner = CommunityUtil.generateUUID();
|
||
Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
|
||
cookie.setMaxAge(60);
|
||
cookie.setPath(contextPath);
|
||
response.addCookie(cookie);
|
||
// 将验证码存入 redis
|
||
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
|
||
redisTemplate.opsForValue().set(redisKey, text, 60, TimeUnit.SECONDS);
|
||
|
||
// 将图片输出给浏览器
|
||
response.setContentType("image/png");
|
||
try {
|
||
ServletOutputStream os = response.getOutputStream();
|
||
ImageIO.write(image, "png", os);
|
||
} catch (IOException e) {
|
||
logger.error("响应验证码失败", e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 验证用户输入的图片验证码是否和redis中存入的是否相等
|
||
*
|
||
* @param kaptchaOwner 从 cookie 中取出的 kaptchaOwner
|
||
* @param checkCode 用户输入的图片验证码
|
||
* @return 失败则返回原因, 验证成功返回 "",
|
||
*/
|
||
private String checkKaptchaCode(String kaptchaOwner, String checkCode) {
|
||
if (StringUtils.isBlank(checkCode)) {
|
||
return "未发现输入的图片验证码";
|
||
}
|
||
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
|
||
String kaptchaValue = (String) redisTemplate.opsForValue().get(redisKey);
|
||
if (StringUtils.isBlank(kaptchaValue)) {
|
||
return "图片验证码过期";
|
||
} else if (!kaptchaValue.equalsIgnoreCase(checkCode)) {
|
||
return "图片验证码错误";
|
||
}
|
||
return "";
|
||
}
|
||
|
||
/**
|
||
* 用户登录
|
||
* @param username 用户名
|
||
* @param password 密码
|
||
* @param code 验证码
|
||
* @param rememberMe 是否记住我(点击记住我后,凭证的有效期延长)
|
||
* @param model
|
||
* @param kaptchaOwner 从 cookie 中取出的 kaptchaOwner
|
||
* @param response
|
||
* @return
|
||
*/
|
||
@PostMapping("/login")
|
||
public String login(@RequestParam("username") String username,
|
||
@RequestParam("password") String password,
|
||
@RequestParam("code") String code,
|
||
@RequestParam(value = "rememberMe", required = false) boolean rememberMe,
|
||
Model model, HttpServletResponse response,
|
||
@CookieValue("kaptchaOwner") String kaptchaOwner) {
|
||
// 检查验证码
|
||
String kaptcha = null;
|
||
if (StringUtils.isNotBlank(kaptchaOwner)) {
|
||
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
|
||
kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
|
||
}
|
||
|
||
if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)) {
|
||
model.addAttribute("codeMsg", "验证码错误");
|
||
return "/site/login";
|
||
}
|
||
|
||
// 凭证过期时间(是否记住我)
|
||
int expiredSeconds = rememberMe ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
|
||
// 验证用户名和密码
|
||
Map<String, Object> map = userService.login(username, password, expiredSeconds);
|
||
if (map.containsKey("ticket")) {
|
||
// 账号和密码均正确,则服务端会生成 ticket,浏览器通过 cookie 存储 ticket
|
||
Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
|
||
cookie.setPath(contextPath); // cookie 有效范围
|
||
cookie.setMaxAge(expiredSeconds);
|
||
response.addCookie(cookie);
|
||
return "redirect:/index";
|
||
}
|
||
else {
|
||
model.addAttribute("usernameMsg", map.get("usernameMsg"));
|
||
model.addAttribute("passwordMsg", map.get("passwordMsg"));
|
||
return "/site/login";
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 用户登出
|
||
* @param ticket 设置凭证状态为无效
|
||
* @return
|
||
*/
|
||
@GetMapping("/logout")
|
||
public String logout(@CookieValue("ticket") String ticket) {
|
||
userService.logout(ticket);
|
||
SecurityContextHolder.clearContext();
|
||
return "redirect:/login";
|
||
}
|
||
|
||
/**
|
||
* 重置密码
|
||
*/
|
||
@PostMapping("/resetPwd")
|
||
@ResponseBody
|
||
public Map<String, Object> resetPwd(@RequestParam("username") String username,
|
||
@RequestParam("password") String password,
|
||
@RequestParam("emailVerifyCode") String emailVerifyCode,
|
||
@RequestParam("kaptchaCode") String kaptcha,
|
||
Model model,
|
||
@CookieValue("kaptchaOwner") String kaptchaOwner) {
|
||
Map<String, Object> map = new HashMap<>(4);
|
||
// 检查图片验证码
|
||
String kaptchaCheckRst = checkKaptchaCode(kaptchaOwner, kaptcha);
|
||
if (StringUtils.isNotBlank(kaptchaCheckRst)) {
|
||
map.put("status", "1");
|
||
map.put("errMsg", kaptchaCheckRst);
|
||
}
|
||
// 检查邮件验证码
|
||
String emailVerifyCodeCheckRst = checkRedisResetPwdEmailCode(username, emailVerifyCode);
|
||
if (StringUtils.isNotBlank(emailVerifyCodeCheckRst)) {
|
||
map.put("status", "1");
|
||
map.put("errMsg", emailVerifyCodeCheckRst);
|
||
}
|
||
// 执行重置密码操作
|
||
Map<String, Object> stringObjectMap = userService.doResetPwd(username, password);
|
||
String usernameMsg = (String) stringObjectMap.get("errMsg");
|
||
if (StringUtils.isBlank(usernameMsg)) {
|
||
map.put("status", "0");
|
||
map.put("msg", "重置密码成功!");
|
||
map.put("target", "/login");
|
||
}
|
||
return map;
|
||
}
|
||
|
||
/**
|
||
* 发送邮件验证码(用于重置密码)
|
||
*
|
||
* @param kaptchaOwner 从 cookie 中取出的 kaptchaOwner
|
||
* @param kaptcha 用户输入的图片验证码
|
||
* @param username 用户输入的需要找回的账号
|
||
*/
|
||
@PostMapping("/sendEmailCodeForResetPwd")
|
||
@ResponseBody
|
||
public Map<String, Object> sendEmailCodeForResetPwd(Model model, @CookieValue("kaptchaOwner") String kaptchaOwner,
|
||
@RequestParam("kaptcha") String kaptcha,
|
||
@RequestParam("username") String username) {
|
||
Map<String, Object> map = new HashMap<>(3);
|
||
// 检查图片验证码
|
||
String kaptchaCheckRst = checkKaptchaCode(kaptchaOwner, kaptcha);
|
||
if (StringUtils.isNotBlank(kaptchaCheckRst)) {
|
||
map.put("status", "1");
|
||
map.put("errMsg", kaptchaCheckRst);
|
||
}
|
||
Map<String, Object> stringObjectMap = userService.doSendEmailCode4ResetPwd(username);
|
||
String usernameMsg = (String) stringObjectMap.get("errMsg");
|
||
if (StringUtils.isBlank(usernameMsg)) {
|
||
map.put("status", "0");
|
||
map.put("msg", "已经往您的邮箱发送了一封验证码邮件, 请查收!");
|
||
}
|
||
return map;
|
||
}
|
||
|
||
/**
|
||
* 检查 邮件 验证码
|
||
*
|
||
* @param username 用户名
|
||
* @param checkCode 用户输入的图片验证码
|
||
* @return 验证成功 返回"", 失败则返回原因
|
||
*/
|
||
private String checkRedisResetPwdEmailCode(String username, String checkCode) {
|
||
if (StringUtils.isBlank(checkCode)) {
|
||
return "未发现输入的邮件验证码";
|
||
}
|
||
final String redisKey = "EmailCode4ResetPwd:" + username;
|
||
String emailVerifyCodeInRedis = (String) redisTemplate.opsForValue().get(redisKey);
|
||
if (StringUtils.isBlank(emailVerifyCodeInRedis)) {
|
||
return "邮件验证码已过期";
|
||
} else if (!emailVerifyCodeInRedis.equalsIgnoreCase(checkCode)) {
|
||
return "邮件验证码错误";
|
||
}
|
||
return "";
|
||
}
|
||
|
||
|
||
}
|