package cn.wisenergy.chnmuseum.party.web.controller; import cn.wisenergy.chnmuseum.party.auth.SHA256PasswordEncryptionService; import cn.wisenergy.chnmuseum.party.auth.util.JwtTokenUtil; import cn.wisenergy.chnmuseum.party.common.checkcode.SpecCaptcha; import cn.wisenergy.chnmuseum.party.common.enums.AuditOperationEnum; import cn.wisenergy.chnmuseum.party.common.enums.AuditStatusEnum; import cn.wisenergy.chnmuseum.party.common.log.MethodLog; import cn.wisenergy.chnmuseum.party.common.log.OperModule; import cn.wisenergy.chnmuseum.party.common.log.OperType; import cn.wisenergy.chnmuseum.party.model.Audit; import cn.wisenergy.chnmuseum.party.model.Role; import cn.wisenergy.chnmuseum.party.model.TUser; import cn.wisenergy.chnmuseum.party.model.Menu; import cn.wisenergy.chnmuseum.party.service.RoleService; import cn.wisenergy.chnmuseum.party.service.impl.TUserServiceImpl; import cn.wisenergy.chnmuseum.party.service.impl.MenuServiceImpl; import cn.wisenergy.chnmuseum.party.web.controller.base.BaseController; import com.alibaba.fastjson.JSONObject; import io.swagger.annotations.Api; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.DisabledAccountException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.time.LocalDate; import java.util.*; import java.util.concurrent.TimeUnit; /** * shiro权限控制登录Controller */ @Api(tags = "登录接口") @RestController public class LoginController extends BaseController { private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class); @Resource private StringRedisTemplate stringRedisTemplate; @Resource private TUserServiceImpl userService; @Resource private RoleService roleService; @Resource private MenuServiceImpl menuService; @Resource private SysLogController sysLogController; private static final String SHIRO_JWT_TOKEN = "shiro:jwt:token:"; //用户登录次数计数 redisKey 前缀 private String SHIRO_LOGIN_COUNT = "shiro_login_count_"; //用户登录是否被锁定 一小时 redisKey 前缀 private String SHIRO_IS_LOCK = "shiro_is_lock_"; // 未授权跳转的页面 @RequestMapping(value = "403", method = RequestMethod.GET) public void noPermissions(HttpServletResponse response) throws IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json;charset=utf-8"); response.setStatus(403); response.getWriter().write("{\"status\":403,\"message\":\"Unauthorized!\"}"); } /** * 管理员ajax登录请求 后端用户登录 * * @param username * @param password * @return */ @RequestMapping(value = "ajaxLogin", method = RequestMethod.POST) public ResponseEntity<Map<String, Object>> ajaxLogin(@RequestParam(value = "username", required = true) String username, @RequestParam(value = "password", required = true) String password, // @RequestParam(value = "captcha", required = true) String captcha, HttpServletRequest request) { Map<String, Object> resultMap = new LinkedHashMap<>(); // String captchaId = request.getHeader("CaptchaId"); // if (StringUtils.isNotBlank(captcha)) { // if (StringUtils.isNotBlank(captchaId)) { // String uuidCap = stringRedisTemplate.opsForValue().get(captchaId); // if (StringUtils.isNotBlank(uuidCap)) { // if (!uuidCap.trim().equalsIgnoreCase(captcha.trim())) { // stringRedisTemplate.delete(captchaId); // resultMap.put("status", 400); // resultMap.put("message", "验证码不正确!"); // return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resultMap); // } // } else { // stringRedisTemplate.delete(captchaId); // resultMap.put("status", 400); // resultMap.put("message", "验证码已失效,请刷新页面!"); // return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resultMap); // } // } else { // //stringRedisTemplate.delete(captchaId); // resultMap.put("status", 400); // resultMap.put("message", "验证码获取失败!"); // return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resultMap); // } // } else { // stringRedisTemplate.delete(captchaId); // resultMap.put("status", 400); // resultMap.put("message", "验证码不能为空!"); // return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resultMap); // } // stringRedisTemplate.delete(captchaId); TUser user; if (StringUtils.isNoneBlank(username)) { try { //访问一次,计数一次 ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue(); if ("LOCK".equals(opsForValue.get(SHIRO_IS_LOCK + username))) { resultMap.put("resultCode", "500"); resultMap.put("message", "由于密码输入错误次数大于5次,12小时内帐号已禁止登录!请您联系相关管理人员。"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resultMap); } user = userService.selectByUsername(username); if (user == null) { resultMap.put("resultCode", "500"); resultMap.put("message", "用户名或密码不正确!"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resultMap); } if (AuditOperationEnum.DISABLE.name().equals(user.getStatus())) { resultMap.put("resultCode", "500"); resultMap.put("message", "此帐号已禁用,请联系管理员!"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resultMap); } if (user.getPermanent()!=null&&!user.getPermanent()) { if (user.getEffectiveDate().isAfter(LocalDate.now())||user.getExiredDate().isBefore(LocalDate.now())) { resultMap.put("resultCode", "500"); resultMap.put("message", "此帐号已失效,请联系管理员!"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resultMap); } } byte[] salt = user.getPasswordSalt(); String s1 = new String(SHA256PasswordEncryptionService.createPasswordHash(password, salt)); if (!new String(SHA256PasswordEncryptionService.createPasswordHash(password, salt)).equals(new String(user.getPasswordHash()))) { opsForValue.increment(SHIRO_LOGIN_COUNT + username, 1); //计数大于5时,设置用户被锁定一小时 String s = opsForValue.get(SHIRO_LOGIN_COUNT + username); if (StringUtils.isNotBlank(s)) { if (Integer.parseInt(s) >= 5) { opsForValue.set(SHIRO_IS_LOCK + username, "LOCK"); stringRedisTemplate.expire(SHIRO_IS_LOCK + username, 12, TimeUnit.HOURS); } } throw new IncorrectCredentialsException("用户名或密码不正确!"); } List<Role> roles = roleService.selectRoleByUserId(user.getId()); List<String> list1 = new ArrayList<>(); //获取当前用户角色拥有菜单 List<Menu> userMenuPerms = new ArrayList<>(); if (roles!=null&&roles.get(0)!=null) { roles.stream().forEach(r -> list1.add(r.getId())); user.setRoleList(list1); userMenuPerms = this.menuService.getUserMenuPerms(list1); } //登录时插入系统日志 String operationContent = username + "登录本系统"; if (user.getOrgName() != null) { operationContent += ",机构" + user.getOrgName(); } this.sysLogController.insertSysLog(operationContent,user); String token = JwtTokenUtil.sign(username, user.getId()); // 将token信息存入Redis stringRedisTemplate.opsForValue().set(SHIRO_JWT_TOKEN + token, user.getId(), 240, TimeUnit.MINUTES); resultMap.put("user", user); resultMap.put("token", token); resultMap.put("menuList", userMenuPerms); resultMap.put("resultCode", "200"); resultMap.put("message", "登录成功"); return ResponseEntity.ok(resultMap); } catch (Exception e) { resultMap.put("resultCode", "500"); resultMap.put("message", e.getMessage()); } } return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resultMap); } @RequestMapping(value = "logout", method = RequestMethod.GET) public ResponseEntity<JSONObject> logout() { String token = request.getHeader("Authorization"); try { if (StringUtils.isNotBlank(token)) { // SecurityUtils.getSubject().logout(); this.stringRedisTemplate.delete(SHIRO_JWT_TOKEN + token); } JSONObject resultMap = new JSONObject(); resultMap.put("resultCode", "200"); resultMap.put("message", "成功"); resultMap.put("data", ""); return ResponseEntity.ok(resultMap); } catch (Exception e) { LOGGER.error("注销错误!", e); } return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } @RequestMapping(value = {"/verifyCode"}, method = {RequestMethod.GET}) public void verifyCode(HttpServletRequest request, HttpServletResponse response, Integer width, Integer height) { String uuid = UUID.randomUUID().toString(); try { SpecCaptcha iVerifyCodeGen; if ((width != null && width > 0) && (height != null && height > 0)) { iVerifyCodeGen = new SpecCaptcha(width, height); } else { iVerifyCodeGen = new SpecCaptcha(); } response.addHeader("CaptchaId", uuid); response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0L); response.setContentType("image/jpeg"); String out = iVerifyCodeGen.out(response.getOutputStream()); this.stringRedisTemplate.opsForValue().set(uuid, out, 1800L); } catch (IOException e) { LOGGER.info("", e); } } @RequestMapping(value = {"/verifyCode1"}, method = {RequestMethod.GET}, produces = MediaType.IMAGE_JPEG_VALUE) public @ResponseBody byte[] verifyCode1(HttpServletRequest request, HttpServletResponse response, Integer width, Integer height) { String uuid = UUID.randomUUID().toString(); ByteArrayOutputStream baos = null; try { SpecCaptcha iVerifyCodeGen; if ((width != null && width > 0) && (height != null && height > 0)) { iVerifyCodeGen = new SpecCaptcha(width, height); } else { iVerifyCodeGen = new SpecCaptcha(); } response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0L); response.setHeader("Access-Control-Allow-Headers", "CaptchaId"); response.setHeader("Access-Control-Expose-Headers", "CaptchaId"); response.addHeader("CaptchaId", uuid); baos = new ByteArrayOutputStream(); String out = iVerifyCodeGen.out(baos); this.stringRedisTemplate.opsForValue().set(uuid, out, 1800L); return baos.toByteArray(); } catch (Exception e) { LOGGER.info("", e); } finally { if (baos != null) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } }