package com.landtool.lanbase.modules.sys.controller; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URLEncoder; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.StringUtils; import org.apache.shiro.web.util.SavedRequest; import org.apache.shiro.web.util.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.alibaba.druid.support.json.JSONUtils; import com.alibaba.fastjson.JSONObject; import com.google.code.kaptcha.Constants; import com.google.code.kaptcha.Producer; import com.landtool.lanbase.common.Constant; import com.landtool.lanbase.common.annotation.LogLogininfo; import com.landtool.lanbase.common.exception.LanbaseException; import com.landtool.lanbase.common.shiro.ShiroToken; import com.landtool.lanbase.common.utils.CoderUtils; import com.landtool.lanbase.common.utils.HttpUtils; import com.landtool.lanbase.common.utils.RedisUtils; import com.landtool.lanbase.common.utils.Result; import com.landtool.lanbase.common.utils.ShiroUtils; import com.landtool.lanbase.config.SysTemPropertyConfig; import com.landtool.lanbase.modules.org.entity.OrgUser; import com.landtool.lanbase.modules.org.service.OrgUserService; import com.landtool.lanbase.modules.sys.redis.OnlineUserRedis; import com.landtool.lanbase.modules.sys.service.SysUserTokenService; import springfox.documentation.annotations.ApiIgnore; /** * @author lanbase * @Description: TODO(登录相关) * @date 2017-6-23 15:07 */ @RestController @ApiIgnore() public class SysLoginController extends AbstractController { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private Producer producer; @Autowired private OrgUserService orgUserService; @Autowired private SysUserTokenService sysUserTokenService; @Autowired private SysTemPropertyConfig sysConfig; @Autowired private OnlineUserRedis onlineUserRedis; @Autowired private RedisUtils redisUtils; /** * 在线人数map */ private static ConcurrentHashMap onlineuser=new ConcurrentHashMap(); /** * 首页 * * @param request * @param response * @throws IOException */ @RequestMapping(value = "/", method = RequestMethod.GET) public void hutaiadmin(HttpServletRequest request, HttpServletResponse response) throws IOException { response.sendRedirect("/res/ZiYuanZhongXin/index?Menu=ZYZX&menuId=07"); // cannot call sendRedirect() after the response has been commited // 1、resopnse 重定向后没有return // 2、重定向后还有重定向,重复的重定向 return; } @RequestMapping("/captcha.jpg") public void captcha(HttpServletResponse response) throws ServletException, IOException { response.setHeader("Cache-Control", "no-store, no-cache"); response.setContentType("image/jpeg"); // 生成文字验证码 String text = producer.createText(); // 生成图片验证码 BufferedImage image = producer.createImage(text); // 保存到shiro session ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text); ServletOutputStream out = response.getOutputStream(); ImageIO.write(image, "jpg", out); IOUtils.closeQuietly(out); } /** * 获取登录错误次数 */ @RequestMapping(value = "/sys/getLoginErrorTimes", method = RequestMethod.GET) public Result getLoginErrorTimes() { Object errorTimes = ShiroUtils.getSessionAttribute(Constant.LOGIN_ERROR_TIMES); return Result.ok().put("errorTimes", errorTimes); } /** * 登录 */ @LogLogininfo("登录") @RequestMapping(value = "/sys/login", method = RequestMethod.POST) public Result login(String username, String password, String captcha) throws IOException { Object _login_errors = ShiroUtils.getSessionAttribute(Constant.LOGIN_ERROR_TIMES); if (_login_errors == null) { _login_errors = 0; } long errorTimes = Long.valueOf(_login_errors.toString()); // 用户信息 OrgUser user = orgUserService.queryByUserName(username); // 账号不存在 if (user == null) { ShiroUtils.setSessionAttribute(Constant.LOGIN_ERROR_TIMES, ++errorTimes); return Result.error("账号不存在").put("errorTimes", errorTimes); } // 密码错误 try { if (!user.getPassword().equals(CoderUtils.lantuEncryptMD5(password))) { ShiroUtils.setSessionAttribute(Constant.LOGIN_ERROR_TIMES, ++errorTimes); return Result.error("密码不正确").put("errorTimes", errorTimes); } } catch (Exception e) { e.printStackTrace(); } // 验证码 if (errorTimes >= 3) { String kaptcha = getKaptcha(Constants.KAPTCHA_SESSION_KEY); if (!captcha.equalsIgnoreCase(kaptcha)) { ShiroUtils.setSessionAttribute(Constant.LOGIN_ERROR_TIMES, ++errorTimes); return Result.error("验证码不正确").put("errorTimes", errorTimes); } } // 账号锁定 if (Constant.UserStatus.DISABLE.getValue() == user.getUserstatus()) { ShiroUtils.setSessionAttribute(Constant.LOGIN_ERROR_TIMES, ++errorTimes); return Result.error("账号已被锁定,请联系管理员").put("errorTimes", errorTimes); } // 生成token,并保存到数据库 Map result = sysUserTokenService.createToken(user.getUserid()); Result r = Result.ok().put(result); return r; } private String getLoginNamefromXml(HttpServletRequest request) throws Exception { String username = ""; Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(true); username = session.getAttribute("shirousername") == null ? "" : session.getAttribute("shirousername").toString(); logger.debug("4----shirousername:" + session.getAttribute("shirousername") + (session.getId())); if (org.springframework.util.StringUtils.isEmpty(username)) { String CasHost = sysConfig.getCasHost();// https://cas.nmsmp.com/cas/ String loginUrl = sysConfig.getLoginUrl(); // http://127.0.0.1:8082/login String ticket = request.getParameter("ticket"); if (!org.springframework.util.StringUtils.isEmpty(ticket)) { String server = getOldQueryString(request); String url = CasHost.replace("https", "http"); String validateurl = url + "serviceValidate?ticket=" + ticket + "&service=" + loginUrl + "?oldurl=" + URLEncoder.encode(server); ; logger.debug("2----ServiceValidate:" + validateurl); String casxml; casxml = HttpUtils.get(validateurl); logger.debug(casxml); Integer index = casxml.indexOf(""); Integer end = casxml.indexOf(""); if (index > 0) { username = casxml.substring(index + 10, end); } } } return username; } @LogLogininfo("登录") @RequestMapping(value = "/index", method = RequestMethod.GET) @ResponseBody public void index(HttpServletRequest request, HttpServletResponse response) throws IOException { String username = request.getRemoteUser(); response.setCharacterEncoding("utf-8"); response.setContentType("text/plain"); response.getWriter().write(username + "登陆成功!"); } /** * oa门户反验证 获取地址上的validatename,调用反验证接口获取结果,为true,则允许登录 */ public JSONObject portallogin(HttpServletRequest request) { String result = ""; String querystring = request.getQueryString(); String username = ""; if (querystring != null) { String par[] = querystring.split("&"); for (int i = 0; i < par.length; i++) { String a = par[i].split("=")[0]; String v = par[i].split("=")[1]; if (a.equals("validateNumber")) { String validateurl = "http://192.168.4.50/services/PortalLoginService/ValidLoginUser?validateNumber=" + v; try { result = HttpUtils.get(validateurl); } catch (Exception e) { logger.info(result); e.printStackTrace(); } } if (a.equals("userName")) { username = v; } } int start = result.indexOf(""); int end = result.indexOf(""); if (start != -1 && end != -1) { JSONObject json = JSONObject.parseObject(result.substring(start + 11, end)); json.put("username", username); return json; } } return null; } /** * CAS登陆成功后调用此方法创建本系统的token * * @param request * @param response * @return * @throws Exception */ @LogLogininfo("登录") @RequestMapping(value = "/login", method = RequestMethod.GET) public void login(HttpServletRequest request, HttpServletResponse response) throws Exception { String username = request.getRemoteUser(); if (StringUtils.hasText(username)) {// 已经登录shiro String oldUrl = getOldParameterPath(request); response.sendRedirect(oldUrl); // WebUtils.issueRedirect(request, response, oldUrl); // } else { // // // oa门户登录判断 // JSONObject validateresult = portallogin(request); // if (validateresult != null && "true".equals(validateresult.getString("validateResult"))) { // String oldUrl = getOldParameterPath(request); // Subject subject = SecurityUtils.getSubject(); // ShiroToken shiroToken = new ShiroToken(validateresult.getString("username"), true); // subject.login(shiroToken); // WebUtils.issueRedirect(request, response, oldUrl); } else { username = getLoginNamefromXml(request); // username="kanglinchong"; // username="liujin"; // username="hanzhicong"; if (StringUtils.hasText(username)) { OrgUser user = orgUserService.queryByUserName(username); // 账号不存在 if (user == null) { response.getWriter().write("[" + username + "]账号不存在或未注册到系统"); return; } Subject subject = SecurityUtils.getSubject(); ShiroToken shiroToken = new ShiroToken(username, true); if (!subject.isAuthenticated()) { subject.login(shiroToken); logger.debug("8----loginshiro:"); } //这里算用户登录成功 ,存入名称和当前毫秒数kv入在线map add by zsx onlineUserRedis.saveOnlineUser(username,subject.getSession()); Session session = subject.getSession(true); session.setAttribute("shirousername", username); // session.setMaxInactiveInterval(sysConfig.getSessionTimeOut());// // 设置Session的超时时间 // 单位秒 logger.debug("3----shirousername:" + session.getAttribute("shirousername").toString() + (session.getId())); String oldUrl = getOldQueryString(request); logger.debug("3----RedirectOldurl:" + oldUrl); // WebUtils.issueRedirect(request, response, oldUrl); response.sendRedirect(oldUrl); } else { String CasHost = sysConfig.getCasHost();// https://cas.nmsmp.com/cas/ String loginUrl = sysConfig.getLoginUrl(); // http://127.0.0.1:8082/login String oldurl = getOldSessionPath(request); if (StringUtils.hasText(oldurl)) { CasHost += "login?service=" + loginUrl + "?oldurl=" + URLEncoder.encode(oldurl); } logger.debug("1----RedirectCasloginUrl:" + CasHost); response.sendRedirect(CasHost);// 用户名不存在跳转回登录页面 } } } private String getOldQueryString(HttpServletRequest request) { String server = request.getQueryString(); String ticket = request.getParameter("ticket"); if (!org.springframework.util.StringUtils.isEmpty(ticket)) { server = server.replace("ticket=" + ticket, ""); if (server.endsWith("&")) server = server.substring(0, server.length() - 1); } server = server.replace("oldurl=", ""); return server; } /*** * 获取原始访问路径 * * @return */ private String getOldParameterPath(HttpServletRequest request) { String oldUrl = request.getParameter("oldurl"); oldUrl = (oldUrl == null) ? "/" : oldUrl; return oldUrl; } /*** * 获取原始访问路径 * * @return */ private String getOldSessionPath(HttpServletRequest request) { String oldurl = getOldParameterPath(request); if (oldurl == "/") { Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(); SavedRequest req = (SavedRequest) session.getAttribute(WebUtils.SAVED_REQUEST_KEY); oldurl = (req == null) ? "" : req.getRequestUrl(); } return oldurl; } /** * CAS登陆成功后调用此方法创建本系统的token 返回jsonp * * @param request * @param response * @return */ @LogLogininfo("登录") @RequestMapping(value = "/sys/caslogin2", method = RequestMethod.GET) @ResponseBody public String caslogin2(HttpServletRequest request, HttpServletResponse response) { String callbackFunName = request.getParameter("callback"); // js回调函数名称 if (callbackFunName == null || callbackFunName.isEmpty()) { callbackFunName = "casloginCallback"; } response.setCharacterEncoding("utf-8"); response.setContentType("text/plain"); return "";// getJsonp(caslogin(request, response), callbackFunName); } /** * 转化为jsonp字符串 * * @param map * @param callbackFunName * @return */ private String getJsonp(Map map, String callbackFunName) { String jsonp = JSONUtils.toJSONString(map); return callbackFunName + "(" + jsonp + ")"; } /** * 退出 * * @throws IOException */ @LogLogininfo("登出") @RequestMapping(value = "/logout") public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException { Subject subject = SecurityUtils.getSubject(); subject.logout(); ////移除在线人数 add by zsx onlineUserRedis.cleanLogoutUser(subject.getSession()); String CasHost = sysConfig.getCasHost(); String logoutUrl = CasHost + "logout?service=" + CasHost + "login"; WebUtils.issueRedirect(request, response, logoutUrl); // sysUserTokenService.logout(getUserId()); // return Result.ok(); } /** * 从session中获取记录的验证码 */ private String getKaptcha(String key) { Object kaptcha = ShiroUtils.getSessionAttribute(key); if (kaptcha == null) { throw new LanbaseException("验证码已失效"); } ShiroUtils.getSession().removeAttribute(key); return kaptcha.toString(); } // /** // * 定时判断,查询用户最近一次操作时间 若最近一次时间超过5分钟,则判断用户下线 // */ // @Scheduled(fixedRate=2*60*1000) // public void cleanMayDownUser(){ // onlineUserRedis.removeDownlineUser(); // } }