登陆注册
- 核心思路就是你登陆注册,我判断是否合法,然后创建Ticket,下发Ticket;
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128public class LoginController {private static final Logger logger = LoggerFactory.getLogger(LoginController.class);UserService userService;/*** regLogin 注册和登陆的处理;默认会跳转到登录页面* 该页面可以登陆也可以注册** @param model 通过model传递到view,view再通过input传递next值* @param next 指之前浏览的页面,登陆注册完就可以跳转过去* @return*/"/reglogin"}, method = {RequestMethod.GET})(path = {public String regLogin(Model model,@RequestParam(value = "next", defaultValue = "") String next) {model.addAttribute("next", next);return "login";}/*** reg register的简写;* 主要功能就是看看用户能不能进行注册;* 通过map得到的ticket跳转响应的页面** @param model model* @param username 用户名* @param password 密码* @param next 下一个跳转的页面* @param rememberme 是否记住* @param response 响应* @return*/"/reg"}, method = RequestMethod.POST)(path = {public String reg(Model model,@RequestParam("username") String username,@RequestParam("password") String password,@RequestParam(value = "next", defaultValue = "") String next,@RequestParam(value = "rememberme", defaultValue = "false") boolean rememberme,HttpServletResponse response) {try {Map<String, String> map = userService.register(username, password);return checkTicket(model, next, rememberme, response, map);} catch (Exception e) {logger.error("注册异常" + e.getMessage());return "login";}}/*** 登陆主要就是需要查看用户是不是合法的;* 通过userService返回的map,来获取ticket,* 然后做出相应跳转** @param model* @param username* @param password* @param rememberme 是否记住,决定于是否下发cookie* @param next 登录后要跳转的页面* @param response 通过响应来下发cookie* @return*/"/login"}, method = RequestMethod.POST)(path = {public String login(Model model,@RequestParam("username") String username,@RequestParam("password") String password,@RequestParam(value = "rememberme", defaultValue = "false") boolean rememberme,@RequestParam(value = "next", defaultValue = "") String next,HttpServletResponse response) {try {Map<String, String> map = userService.login(username, password);return checkTicket(model, next, rememberme, response, map);} catch (Exception e) {logger.error("注册异常" + e.getMessage());return "login";}}/*** 将ticket的status置为0,也就是说不能用了,* 这样用户就需要重新登陆了,因为本地的cookie值 已经失效;* 因为服务器表示你这ticket不能用啊;** @param ticket* @return*/"/logout"}, method = RequestMethod.GET)(path = {public String logout(@CookieValue("ticket") String ticket) {userService.logout(ticket);return "redirect:/";}/*** 检验ticket,通过map得到ticket,如果map没有ticket* 说明这注册或者登陆不合法,返回map中的msg给view,显示错误信息;* 拿到ticket就下发cookie,默认是session,如果点击记住我,时间就是* 5天,然后进行跳转,如果有next就跳转next* @param model* @param next* @param rememberme* @param response* @param map* @return*/private String checkTicket(Model model, @RequestParam(value = "next", defaultValue = "") String next, @RequestParam(value = "rememberme", defaultValue = "false") boolean rememberme, HttpServletResponse response, Map<String, String> map) {if (map.containsKey("ticket")) {Cookie cookie = new Cookie("ticket", map.get("ticket"));cookie.setPath("/");if (rememberme) {cookie.setMaxAge(3600 * 24 * 5);}response.addCookie(cookie);if (StringUtils.isNotBlank(next)) {return "redirect:" + next;}return "redirect:/";} else {model.addAttribute("msg", map.get("msg"));return "login";}}}
Ticket
把Ticket叫做T票也不是没有道理的;简单来说就是服务器会制造门票,然后下发给客户端,如果你丢了(cookie过期T票就没了),就不能访问了;服务器也可以主动的将门票设置为不合法,要求你重新登陆一遍
因此存放在服务器里的ticket有一个过期时间,本地cookie也有一个过期时间;
- 可以通过UUID来生成ticket;123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990/*** 判断注册是否合法的函数* 如果合法的话,就添加盐,盐+password通过md5算法增加保密性;* 将用户加入数据库,添加ticket(服务器),然后下发(客户端)* @param username* @param password* @return*/public Map<String, String> register(String username, String password) {Map<String, String> map = new HashMap<>();if (StringUtils.isBlank(username)) {map.put("msg", "用户名不能为空");}if (StringUtils.isBlank(password)) {map.put("msg", "密码不能为空");}User user = userDAO.selectByName(username);if (user != null) {map.put("msg", "该用户已经被注册");return map;}user = new User();user.setName(username);user.setSalt(UUID.randomUUID().toString().substring(0, 5));user.setHeadUrl(String.format("http://images.nowcoder.com/head/%dt.png", new Random().nextInt(1000)));//md5 需要重看user.setPassword(WendaUtil.MD5(password + user.getSalt()));userDAO.addUser(user);String ticket = addLoginTicket(user.getId());map.put("ticket", ticket);return map;}/*** 验证的登陆是否合法,添加ticket,下发ticket* @param username* @param password* @return*/public Map<String, String> login(String username, String password) {Map<String, String> map = new HashMap<>();if (StringUtils.isBlank(username)) {map.put("msg", "用户名不能为空");}if (StringUtils.isBlank(password)) {map.put("msg", "密码不能为空");}User user = userDAO.selectByName(username);if (user == null) {map.put("msg", "用户名不存在");return map;}if (!WendaUtil.MD5(password + user.getSalt()).equals(user.getPassword())) {map.put("msg", "用户密码错误");return map;}String ticket = addLoginTicket(user.getId());map.put("ticket", ticket);return map;}/*** 增加ticket,注意日期* @param userId* @return*/public String addLoginTicket(int userId) {LoginTicket loginTicket = new LoginTicket();loginTicket.setUserId(userId);Date now = new Date();now.setTime(now.getTime() + 3600L * 24 * 1000 * 1000);loginTicket.setExpired(now);loginTicket.setStatus(0);loginTicket.setTicket(UUID.randomUUID().toString().replace("-", ""));loginTicketDao.addTicket(loginTicket);return loginTicket.getTicket();}/*** 将ticket的status置为1** @param ticket*/public void logout(String ticket) {loginTicketDao.updateStatus(ticket, 1);}
Interceptor
拦截器需要注册
12345678910111213141516171819public class WendaWebConfiguration extends WebMvcConfigurerAdapter {PassportInterceptor passportInterceptor;LoginRequiredInterceptor loginRequiredInterceptor;/*** 添加拦截器,拦截器会按照顺序执行* @param registry*/public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(passportInterceptor);registry.addInterceptor(loginRequiredInterceptor).addPathPatterns("/user/*");super.addInterceptors(registry);}}拦截器针对request
12345678910111213141516171819202122232425262728293031323334353637383940414243444546public class PassportInterceptor implements HandlerInterceptor {LoginTicketDao loginTicketDao;UserDAO userDAO;HostHolder hostHolder;//拦截器是针对request的,有多少次request,就经历多少次拦截器public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String ticket = null;if (request.getCookies() != null) {for (Cookie cookie : request.getCookies()) {if (cookie.getName().equals("ticket")) {ticket = cookie.getValue();break;}}}if (ticket != null) {LoginTicket loginTicket = loginTicketDao.selectByTicket(ticket);if (loginTicket == null || loginTicket.getExpired().before(new Date()) || loginTicket.getStatus() != 0) {return true;}User user = userDAO.selectById(loginTicket.getUserId());hostHolder.setUser(user);}return true;}public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {if (modelAndView != null) {modelAndView.addObject("user", hostHolder.getUser());}}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {hostHolder.clear();}}