Commit d9a76451482d17f2aac7490358f54a7faeec2037

Authored by 王通
1 parent e8da88c9

1.登录密码错误2次加验证码,错4次锁定10分钟,管理员可解锁

2.登录时做弱密码检查,存在弱密码在index页面强制修改密码
3.密码规则加入连续性字符验证,如不能出现123、abc样的连续字符
4.记录最后登录日期
src/main/java/com/bsth/common/Constants.java
1   -package com.bsth.common;
2   -
3   -/**
4   - *
5   - * @ClassName: Constants
6   - * @Description: TODO(常量类)
7   - * @author PanZhao
8   - * @date 2016年3月18日 下午11:06:53
9   - *
10   - */
11   -public class Constants {
12   -
13   - /**
14   - * 不需要拦截的资源
15   - */
16   - public static final String LOGIN = "/user/login/**";
17   - public static final String LOGIN_PAGE = "/login.html";
18   - public static final String ASSETS_URL = "/assets/**";
19   - public static final String FAVICON_URL = "/favicon.ico";
20   - public static final String METRONIC_URL = "/metronic_v4.5.4/**";
21   - public static final String LOGIN_FAILURE = "/user/loginFailure";
22   - public static final String CAPTCHA = "/captcha.jpg";
23   -
24   - // springboot manage health的检测url
25   - public static final String ACTUATOR_MANAGEMENT_HEALTH = "/manage/health";
26   - // 车辆数据同步url
27   - public static final String VEHICLE_DATA_SYNC_URL = "/dataSync/vehicle/api/**";
28   -
29   - //对外的营运数据接口
30   - public static final String SERVICE_INTERFACE = "/companyService/**";
31   -
32   - /**
33   - * 线调部分子页面不做拦截,便于浏览器缓存
34   - */
35   - public static final String XD_CHILD_PAGES = "/real_control_v2/**";
36   - public static final String XD_REAL_GPS = "/gps/real/line";
37   - //public static final String XD_TEMPS = "/pages/control/line/temps/**";
38   -
39   - //车载网关上行接口
40   - public static final String UPSTREAM_URL = "/control/upstream";
41   - //rfid 上传入口
42   - public static final String UP_RFID_URL = "/rfid/**";
43   -
44   - public static final String SESSION_USERNAME = "sessionUserName";
45   - public static final String COMPANY_AUTHORITYS = "cmyAuths";
46   - public static final String STATION_AND_SECTION_COUNT = "/station/updateStationAndSectionCode";
47   -
48   - /**
49   - * 解除调度指令和班次的外键约束
50   - */
51   - public static final String REMOVE_DIRECTIVE_SCH_FK = "update bsth_v_directive_60 set sch=NULL where sch=?";
52   -
53   - /**
54   - * 批量解除调度指令和班次的外键约束
55   - */
56   - public static final String MULTI_REMOVE_DIRECTIVE_SCH_FK = "update bsth_v_directive_60 set sch=NULL where sch in ";
57   -
58   - /**
59   - * 批量解除子任务和班次的外键约束
60   - */
61   - public static final String MULTI_REMOVE_CHILDTASK_SCH_FK = "update bsth_c_s_child_task set schedule=NULL where schedule in ";
62   -}
  1 +package com.bsth.common;
  2 +
  3 +/**
  4 + *
  5 + * @ClassName: Constants
  6 + * @Description: TODO(常量类)
  7 + * @author PanZhao
  8 + * @date 2016年3月18日 下午11:06:53
  9 + *
  10 + */
  11 +public class Constants {
  12 +
  13 + /**
  14 + * 不需要拦截的资源
  15 + */
  16 + public static final String LOGIN = "/user/login/**";
  17 + public static final String LOGIN_PAGE = "/login.html";
  18 + public static final String ASSETS_URL = "/assets/**";
  19 + public static final String FAVICON_URL = "/favicon.ico";
  20 + public static final String METRONIC_URL = "/metronic_v4.5.4/**";
  21 + public static final String LOGIN_FAILURE = "/user/loginFailure";
  22 + public static final String CAPTCHA = "/captcha.jpg";
  23 +
  24 + // springboot manage health的检测url
  25 + public static final String ACTUATOR_MANAGEMENT_HEALTH = "/manage/health";
  26 + // 车辆数据同步url
  27 + public static final String VEHICLE_DATA_SYNC_URL = "/dataSync/vehicle/api/**";
  28 +
  29 + //对外的营运数据接口
  30 + public static final String SERVICE_INTERFACE = "/companyService/**";
  31 +
  32 + /**
  33 + * 线调部分子页面不做拦截,便于浏览器缓存
  34 + */
  35 + public static final String XD_CHILD_PAGES = "/real_control_v2/**";
  36 + public static final String XD_REAL_GPS = "/gps/real/line";
  37 + //public static final String XD_TEMPS = "/pages/control/line/temps/**";
  38 +
  39 + //车载网关上行接口
  40 + public static final String UPSTREAM_URL = "/control/upstream";
  41 + //rfid 上传入口
  42 + public static final String UP_RFID_URL = "/rfid/**";
  43 +
  44 + public static final String SESSION_USERNAME = "sessionUserName";
  45 + public static final String COMPANY_AUTHORITYS = "cmyAuths";
  46 + public static final String STATION_AND_SECTION_COUNT = "/station/updateStationAndSectionCode";
  47 +
  48 + /**
  49 + * 解除调度指令和班次的外键约束
  50 + */
  51 + public static final String REMOVE_DIRECTIVE_SCH_FK = "update bsth_v_directive_60 set sch=NULL where sch=?";
  52 +
  53 + /**
  54 + * 批量解除调度指令和班次的外键约束
  55 + */
  56 + public static final String MULTI_REMOVE_DIRECTIVE_SCH_FK = "update bsth_v_directive_60 set sch=NULL where sch in ";
  57 +
  58 + /**
  59 + * 批量解除子任务和班次的外键约束
  60 + */
  61 + public static final String MULTI_REMOVE_CHILDTASK_SCH_FK = "update bsth_c_s_child_task set schedule=NULL where schedule in ";
  62 +
  63 + public static final String WEAK_CIPHER = "weakCipher";
  64 +}
... ...
src/main/java/com/bsth/controller/sys/UserController.java
1   -package com.bsth.controller.sys;
2   -
3   -import com.bsth.common.Constants;
4   -import com.bsth.common.ResponseCode;
5   -import com.bsth.controller.BaseController;
6   -import com.bsth.controller.sys.dto.CompanyData;
7   -import com.bsth.controller.sys.util.RSAUtils;
8   -import com.bsth.entity.sys.CompanyAuthority;
9   -import com.bsth.entity.sys.SysUser;
10   -import com.bsth.security.util.SecurityUtils;
11   -import com.bsth.service.sys.CompanyAuthorityService;
12   -import com.bsth.service.sys.SysUserService;
13   -import com.google.common.collect.ArrayListMultimap;
14   -import org.apache.commons.lang3.StringUtils;
15   -import org.slf4j.Logger;
16   -import org.slf4j.LoggerFactory;
17   -import org.springframework.beans.factory.annotation.Autowired;
18   -import org.springframework.security.authentication.BadCredentialsException;
19   -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
20   -import org.springframework.security.web.authentication.session.SessionAuthenticationException;
21   -import org.springframework.web.bind.annotation.RequestMapping;
22   -import org.springframework.web.bind.annotation.RequestMethod;
23   -import org.springframework.web.bind.annotation.RequestParam;
24   -import org.springframework.web.bind.annotation.RestController;
25   -
26   -import javax.servlet.http.HttpServletRequest;
27   -import javax.servlet.http.HttpSession;
28   -import java.util.*;
29   -
30   -@RestController
31   -@RequestMapping("user")
32   -public class UserController extends BaseController<SysUser, Integer> {
33   -
34   - Logger logger = LoggerFactory.getLogger(this.getClass());
35   -
36   - @Autowired
37   - SysUserService sysUserService;
38   -
39   - @Autowired
40   - CompanyAuthorityService companyAuthorityService;
41   -
42   - @RequestMapping(value = "/login/jCryptionKey")
43   - public Map<String, Object> jCryptionKey(HttpServletRequest request) {
44   - //公匙返回页面
45   - Map<String, Object> rs = new HashMap<>();
46   - rs.put("publickey", RSAUtils.generateBase64PublicKey());
47   - return rs;
48   - }
49   -
50   - @RequestMapping(value = "/getCurrentUser")
51   - public SysUser getCurrentUser() {
52   - SysUser user = SecurityUtils.getCurrentUser();
53   - return user;
54   - }
55   -
56   - //需要验证码的账号
57   - public static Map<String, Integer> captchaMap = new HashMap<>();
58   -
59   - @RequestMapping(value = "/login", method = RequestMethod.POST)
60   - public Map<String, Object> login(HttpServletRequest request, @RequestParam String userName,
61   - @RequestParam String password, String captcha) {
62   -
63   - Map<String, Object> rs = new HashMap<>();
64   - rs.put("status", ResponseCode.ERROR);
65   - try {
66   - HttpSession session = request.getSession();
67   - rs.put("captcha", session.getAttribute("captcha"));
68   -
69   - if (captchaMap.get(userName) != null && captchaMap.get(userName) >= 3) {
70   - //校验验证码
71   - String verCode = (String) session
72   - .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
73   -
74   - if (StringUtils.isBlank(captcha))
75   - return put(rs, "msg", "请输入验证码");
76   -
77   - if (!verCode.equals(captcha))
78   - return put(rs, "msg", "验证码有误,请刷新后重新输入");
79   - }
80   -
81   - //解密RSA
82   - try {
83   - userName = RSAUtils.decryptBase64(userName);
84   - password = RSAUtils.decryptBase64(password);
85   - } catch (RuntimeException e) {
86   - return put(rs, "msg", "decrypt RSA fail!可能页面已过期,尝试刷新页面。");
87   - }
88   -
89   - SysUser user = sysUserService.findByUserName(userName);
90   - if (null == user)
91   - return put(rs, "msg", "不存在的用户");
92   -
93   - if (!user.isEnabled())
94   - return put(rs, "msg", "该用户已被锁定,请联系管理员");
95   -
96   - // 校验密码
97   - boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
98   - if (!matchStatus) {
99   - rs.put("msg", "密码有误");
100   -
101   - Integer captchSize = captchaMap.get(userName);
102   - if (null == captchSize)
103   - captchSize = 0;
104   -
105   - captchSize++;
106   - captchaMap.put(userName, captchSize);
107   - return rs;
108   - }
109   -
110   - // 登录
111   - SecurityUtils.login(user, request);
112   - //session里写入用户名,webSocket连接时标识身份用
113   - session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
114   -
115   - //获取公司权限数据
116   - List<CompanyAuthority> cmyAuths = companyAuthorityService.findByUser(user);
117   - session.setAttribute(Constants.COMPANY_AUTHORITYS, cmyAuths);
118   -
119   - captchaMap.remove(userName);
120   - rs.put("status", ResponseCode.SUCCESS);
121   - logger.error("用户:" + user.getUserName() + "登录");
122   - } catch (Exception e) {
123   - logger.error("", e);
124   - rs.put("msg", "服务器出现异常,请联系管理员");
125   - }
126   - return rs;
127   - }
128   -
129   - @RequestMapping(value = "/change_user", method = RequestMethod.POST)
130   - public Map<String, Object> changeUser(HttpServletRequest request, @RequestParam String userName,
131   - @RequestParam String password) {
132   -
133   - Map<String, Object> rs = new HashMap<>();
134   - rs.put("status", ResponseCode.ERROR);
135   - try {
136   - HttpSession session = request.getSession();
137   -
138   - SysUser user = sysUserService.findByUserName(userName);
139   - if (null == user)
140   - return put(rs, "msg", "不存在的用户");
141   -
142   - if (!user.isEnabled())
143   - return put(rs, "msg", "该用户已被锁定,请联系管理员");
144   -
145   - // 校验密码
146   - boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
147   - if (!matchStatus)
148   - return put(rs, "msg", "密码有误");
149   -
150   - // 登录
151   - SecurityUtils.login(user, request);
152   - //session里写入用户名,webSocket连接时标识身份用
153   - session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
154   -
155   - //获取公司权限数据
156   - List<CompanyAuthority> cmyAuths = companyAuthorityService.findByUser(user);
157   - session.setAttribute(Constants.COMPANY_AUTHORITYS, cmyAuths);
158   - rs.put("status", ResponseCode.SUCCESS);
159   - } catch (Exception e) {
160   - logger.error("", e);
161   - rs.put("msg", "服务器出现异常,请联系管理员");
162   - }
163   - return rs;
164   - }
165   -
166   - /**
167   - * 返回当前用户的公司权限数据,用于构建页面级联下拉框
168   - *
169   - * @return
170   - */
171   - @RequestMapping("companyData")
172   - public List<CompanyData> companyData(HttpServletRequest request) {
173   - List<CompanyData> rs = new ArrayList<>();
174   - CompanyData companyData;
175   -
176   - ArrayListMultimap<String, CompanyAuthority> map = ArrayListMultimap.create();
177   - List<CompanyAuthority> cmyAuths = (List<CompanyAuthority>) request.getSession().getAttribute(Constants.COMPANY_AUTHORITYS);
178   -
179   - for (CompanyAuthority cAuth : cmyAuths) {
180   - map.put(cAuth.getCompanyCode() + "_" + cAuth.getCompanyName(), cAuth);
181   - }
182   -
183   - Set<String> keys = map.keySet();
184   - String[] temps;
185   - for (String k : keys) {
186   - temps = k.split("_");
187   -
188   - companyData = new CompanyData();
189   - companyData.setCompanyCode(temps[0]);
190   - companyData.setCompanyName(temps[1]);
191   - companyData.setChildren(new ArrayList<CompanyData.ChildrenCompany>());
192   -
193   - cmyAuths = map.get(k);
194   - for (CompanyAuthority c : cmyAuths) {
195   - companyData.getChildren().add(new CompanyData.ChildrenCompany(c.getSubCompanyCode(), c.getSubCompanyName()));
196   - }
197   -
198   - rs.add(companyData);
199   - }
200   -
201   - return rs;
202   - }
203   -
204   - @RequestMapping(value = "/login/captchaStatus")
205   - public int captchaStatus(String userName) {
206   - Integer size = captchaMap.get(userName);
207   - return size == null ? 0 : size;
208   - }
209   -
210   - public Map<String, Object> put(Map<String, Object> rs, String key, Object val) {
211   - rs.put(key, val);
212   - return rs;
213   - }
214   -
215   - /**
216   - * @Title: loginFailure @Description: TODO(查询登录失败的详细信息) @param @param
217   - * request @return String 返回类型 @throws
218   - */
219   - @RequestMapping("/loginFailure")
220   - public String loginFailure(HttpServletRequest request) {
221   - String msg = "";
222   - HttpSession session = request.getSession();
223   -
224   - Object obj = session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
225   -
226   - if (obj instanceof BadCredentialsException)
227   - msg = "登录失败,用户名或密码错误.";
228   - else if (obj instanceof SessionAuthenticationException)
229   - msg = "登录失败,当前策略不允许重复登录.";
230   - session.removeAttribute("SPRING_SECURITY_LAST_EXCEPTION");
231   - return msg;
232   - }
233   -
234   - @RequestMapping("/currentUser")
235   - public SysUser currentUser() {
236   - return SecurityUtils.getCurrentUser();
237   - }
238   -
239   - /**
240   - * @param id 用户ID
241   - * @param enabled 状态
242   - * @return
243   - * @Title changeEnabled
244   - * @Description: TODO(改变用户状态)
245   - */
246   - @RequestMapping("/changeEnabled")
247   - public int changeEnabled(@RequestParam int id, @RequestParam int enabled) {
248   - return sysUserService.changeEnabled(id, enabled);
249   - }
250   -
251   - /**
252   - * @param oldPWD 原始密码
253   - * @param newPWD 新密码
254   - * @param cnewPWD 确认新密码
255   - * @return
256   - * @Title changePWD
257   - * @Description: TODO(修改密码)
258   - */
259   - @RequestMapping(value = "/changePWD", method = RequestMethod.POST)
260   - public String changePWD(@RequestParam String oldPWD, @RequestParam String newPWD, @RequestParam String cnewPWD) {
261   - SysUser sysUser = SecurityUtils.getCurrentUser();
262   - String msg = "";
263   -
264   - //解密RSA
265   - try{
266   - oldPWD = (RSAUtils.decryptBase64(oldPWD));
267   - newPWD = (RSAUtils.decryptBase64(newPWD));
268   - cnewPWD = (RSAUtils.decryptBase64(cnewPWD));
269   - }catch (RuntimeException e) {
270   - return "网络延迟,解密失败,请重新添加!";
271   - }
272   - if (new BCryptPasswordEncoder(4).matches(oldPWD, sysUser.getPassword())) {
273   - if (oldPWD.equals(newPWD)) {
274   - msg = "新密码不能跟原始密码一样!";
275   - } else {
276   - if (newPWD.equals(cnewPWD)) {
277   - sysUserService.changePWD(sysUser.getId(), newPWD);
278   - msg = "修改成功!";
279   - } else {
280   - msg = "新密码两次输入不一致!";
281   - }
282   - }
283   - } else {
284   - msg = "原始密码错误!";
285   - }
286   - return msg;
287   - }
288   -
289   - @RequestMapping(value = "/register", method = RequestMethod.POST)
290   - public Map<String, Object> register(SysUser u) {
291   - return sysUserService.register(u);
292   - }
293   -
294   - // 查询用户下所有下级角色
295   - @RequestMapping(value = "/all_distinct")
296   - public List<SysUser> findAll_distinct() {
297   - return sysUserService.findAll_distinct();
298   - }
299   -
300   - // 重置密码
301   - @RequestMapping(value = "/resetPassword", method = RequestMethod.POST)
302   - public Map<String, Object> resetPassword(@RequestParam Integer id) {
303   - return sysUserService.resetPassword(id);
304   - }
305   -
306   -}
  1 +package com.bsth.controller.sys;
  2 +
  3 +import com.bsth.common.Constants;
  4 +import com.bsth.common.ResponseCode;
  5 +import com.bsth.controller.BaseController;
  6 +import com.bsth.controller.sys.dto.CompanyData;
  7 +import com.bsth.controller.sys.util.RSAUtils;
  8 +import com.bsth.email.entity.EmailBean;
  9 +import com.bsth.entity.sys.CompanyAuthority;
  10 +import com.bsth.entity.sys.Role;
  11 +import com.bsth.entity.sys.SysUser;
  12 +import com.bsth.security.util.SecurityUtils;
  13 +import com.bsth.service.sys.CompanyAuthorityService;
  14 +import com.bsth.service.sys.SysUserService;
  15 +import com.bsth.service.sys.impl.PwdGenerator;
  16 +import com.bsth.util.IpUtils;
  17 +import com.google.common.collect.ArrayListMultimap;
  18 +import org.apache.commons.lang3.StringUtils;
  19 +import org.slf4j.Logger;
  20 +import org.slf4j.LoggerFactory;
  21 +import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.security.authentication.BadCredentialsException;
  23 +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  24 +import org.springframework.security.web.authentication.session.SessionAuthenticationException;
  25 +import org.springframework.web.bind.annotation.RequestMapping;
  26 +import org.springframework.web.bind.annotation.RequestMethod;
  27 +import org.springframework.web.bind.annotation.RequestParam;
  28 +import org.springframework.web.bind.annotation.RestController;
  29 +
  30 +import javax.servlet.http.HttpServletRequest;
  31 +import javax.servlet.http.HttpSession;
  32 +import java.util.*;
  33 +import java.util.regex.Matcher;
  34 +import java.util.regex.Pattern;
  35 +
  36 +@RestController
  37 +@RequestMapping("user")
  38 +public class UserController extends BaseController<SysUser, Integer> {
  39 +
  40 + Logger logger = LoggerFactory.getLogger(this.getClass());
  41 +
  42 + @Autowired
  43 + SysUserService sysUserService;
  44 +
  45 + @Autowired
  46 + CompanyAuthorityService companyAuthorityService;
  47 +
  48 + private Pattern pattern = Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*?[#?!@$%^&*-.]).{8,16}$");
  49 +
  50 + @RequestMapping(value = "/login/jCryptionKey")
  51 + public Map<String, Object> jCryptionKey(HttpServletRequest request) {
  52 + //公匙返回页面
  53 + Map<String, Object> rs = new HashMap<>();
  54 + rs.put("publickey", RSAUtils.generateBase64PublicKey());
  55 + return rs;
  56 + }
  57 +
  58 + @RequestMapping(value = "/getCurrentUser")
  59 + public SysUser getCurrentUser() {
  60 + SysUser user = SecurityUtils.getCurrentUser();
  61 + return user;
  62 + }
  63 +
  64 + //需要验证码的账号
  65 + public static Map<String, Integer> USER_ERRTIMES = new HashMap<>();
  66 + public static Map<String, Long> USER_LOCKTIME = new HashMap<>();
  67 +
  68 + @RequestMapping(value = "/login", method = RequestMethod.POST)
  69 + public Map<String, Object> login(HttpServletRequest request, @RequestParam String userName,
  70 + @RequestParam String password, String captcha) {
  71 +
  72 + Map<String, Object> rs = new HashMap<>();
  73 + rs.put("status", ResponseCode.ERROR);
  74 + try {
  75 + HttpSession session = request.getSession();
  76 + rs.put("captcha", session.getAttribute("captcha"));
  77 +
  78 + //解密RSA
  79 + try {
  80 + userName = RSAUtils.decryptBase64(userName);
  81 + password = RSAUtils.decryptBase64(password);
  82 + } catch (RuntimeException e) {
  83 + return put(rs, "msg", "decrypt RSA fail!可能页面已过期,尝试刷新页面。");
  84 + }
  85 +
  86 + SysUser user = sysUserService.findByUserName(userName);
  87 +
  88 + // 校验用户状态
  89 + if (!user.isEnabled()) {
  90 + return put(rs, "msg", "该用户已被锁定,请联系管理员");
  91 + }
  92 +
  93 + // 校验临时状态
  94 + if (USER_LOCKTIME.get(userName) != null && USER_LOCKTIME.get(userName) >= System.currentTimeMillis()) {
  95 + return put(rs, "msg", "您的账户因密码错误次数过多,处于锁定状态中");
  96 + }
  97 +
  98 + // 校验验证码
  99 + if (USER_ERRTIMES.get(userName) != null && USER_ERRTIMES.get(userName) > 1) {
  100 + String verCode = (String) session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
  101 + if (StringUtils.isBlank(captcha)) {
  102 + return put(rs, "msg", "请输入验证码");
  103 + }
  104 + if (!verCode.equals(captcha)) {
  105 + return put(rs, "msg", "验证码有误,请刷新后重新输入");
  106 + }
  107 + }
  108 +
  109 + // 校验密码
  110 + boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
  111 + if (null == user || !matchStatus) {
  112 + rs.put("msg", "密码有误");
  113 +
  114 + Integer errTimes = USER_ERRTIMES.get(userName);
  115 + if (null == errTimes) {
  116 + errTimes = 0;
  117 + }
  118 + USER_ERRTIMES.put(userName, ++errTimes);
  119 + if (errTimes > 3) {
  120 + USER_LOCKTIME.put(userName, System.currentTimeMillis() + 600000);
  121 + USER_ERRTIMES.put(userName, 0);
  122 + put(rs, "msg", "密码错误4次,账户将被锁定10分钟");
  123 + }
  124 +
  125 + return rs;
  126 + }
  127 +
  128 + // 弱密码检查
  129 + Matcher matcher = pattern.matcher(password);
  130 + if (!matcher.matches()) {
  131 + session.setAttribute(Constants.WEAK_CIPHER, 1);
  132 + }
  133 +
  134 + // 登录
  135 + SecurityUtils.login(user, request);
  136 + sysUserService.recordLoginDate(userName);
  137 + //session里写入用户名,webSocket连接时标识身份用
  138 + session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
  139 +
  140 + //获取公司权限数据
  141 + List<CompanyAuthority> cmyAuths = companyAuthorityService.findByUser(user);
  142 + session.setAttribute(Constants.COMPANY_AUTHORITYS, cmyAuths);
  143 +
  144 + USER_ERRTIMES.remove(userName);
  145 + rs.put("status", ResponseCode.SUCCESS);
  146 + logger.error("用户:" + user.getUserName() + "登录");
  147 + } catch (Exception e) {
  148 + logger.error("", e);
  149 + rs.put("msg", "服务器出现异常,请联系管理员");
  150 + }
  151 + return rs;
  152 + }
  153 +
  154 + @RequestMapping(value = "/change_user", method = RequestMethod.POST)
  155 + public Map<String, Object> changeUser(HttpServletRequest request, @RequestParam String userName,
  156 + @RequestParam String password) {
  157 +
  158 + Map<String, Object> rs = new HashMap<>();
  159 + rs.put("status", ResponseCode.ERROR);
  160 + try {
  161 + HttpSession session = request.getSession();
  162 +
  163 + SysUser user = sysUserService.findByUserName(userName);
  164 + if (null == user)
  165 + return put(rs, "msg", "不存在的用户");
  166 +
  167 + if (!user.isEnabled())
  168 + return put(rs, "msg", "该用户已被锁定,请联系管理员");
  169 +
  170 + // 校验密码
  171 + boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
  172 + if (!matchStatus)
  173 + return put(rs, "msg", "密码有误");
  174 +
  175 + // 登录
  176 + SecurityUtils.login(user, request);
  177 + //session里写入用户名,webSocket连接时标识身份用
  178 + session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
  179 +
  180 + //获取公司权限数据
  181 + List<CompanyAuthority> cmyAuths = companyAuthorityService.findByUser(user);
  182 + session.setAttribute(Constants.COMPANY_AUTHORITYS, cmyAuths);
  183 + rs.put("status", ResponseCode.SUCCESS);
  184 + } catch (Exception e) {
  185 + logger.error("", e);
  186 + rs.put("msg", "服务器出现异常,请联系管理员");
  187 + }
  188 + return rs;
  189 + }
  190 +
  191 + /**
  192 + * 返回当前用户的公司权限数据,用于构建页面级联下拉框
  193 + *
  194 + * @return
  195 + */
  196 + @RequestMapping("companyData")
  197 + public List<CompanyData> companyData(HttpServletRequest request) {
  198 + List<CompanyData> rs = new ArrayList<>();
  199 + CompanyData companyData;
  200 +
  201 + ArrayListMultimap<String, CompanyAuthority> map = ArrayListMultimap.create();
  202 + List<CompanyAuthority> cmyAuths = (List<CompanyAuthority>) request.getSession().getAttribute(Constants.COMPANY_AUTHORITYS);
  203 +
  204 + for (CompanyAuthority cAuth : cmyAuths) {
  205 + map.put(cAuth.getCompanyCode() + "_" + cAuth.getCompanyName(), cAuth);
  206 + }
  207 +
  208 + Set<String> keys = map.keySet();
  209 + String[] temps;
  210 + for (String k : keys) {
  211 + temps = k.split("_");
  212 +
  213 + companyData = new CompanyData();
  214 + companyData.setCompanyCode(temps[0]);
  215 + companyData.setCompanyName(temps[1]);
  216 + companyData.setChildren(new ArrayList<CompanyData.ChildrenCompany>());
  217 +
  218 + cmyAuths = map.get(k);
  219 + for (CompanyAuthority c : cmyAuths) {
  220 + companyData.getChildren().add(new CompanyData.ChildrenCompany(c.getSubCompanyCode(), c.getSubCompanyName()));
  221 + }
  222 +
  223 + rs.add(companyData);
  224 + }
  225 +
  226 + return rs;
  227 + }
  228 +
  229 + @RequestMapping(value = "/login/captchaStatus")
  230 + public int captchaStatus(String userName) {
  231 + Integer size = USER_ERRTIMES.get(userName);
  232 + return size == null ? 0 : size;
  233 + }
  234 +
  235 + public Map<String, Object> put(Map<String, Object> rs, String key, Object val) {
  236 + rs.put(key, val);
  237 + return rs;
  238 + }
  239 +
  240 + /**
  241 + * @Title: loginFailure @Description: TODO(查询登录失败的详细信息) @param @param
  242 + * request @return String 返回类型 @throws
  243 + */
  244 + @RequestMapping("/loginFailure")
  245 + public String loginFailure(HttpServletRequest request) {
  246 + String msg = "";
  247 + HttpSession session = request.getSession();
  248 +
  249 + Object obj = session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
  250 +
  251 + if (obj instanceof BadCredentialsException)
  252 + msg = "登录失败,用户名或密码错误.";
  253 + else if (obj instanceof SessionAuthenticationException)
  254 + msg = "登录失败,当前策略不允许重复登录.";
  255 + session.removeAttribute("SPRING_SECURITY_LAST_EXCEPTION");
  256 + return msg;
  257 + }
  258 +
  259 + @RequestMapping("/currentUser")
  260 + public SysUser currentUser() {
  261 + return SecurityUtils.getCurrentUser();
  262 + }
  263 +
  264 + /**
  265 + * @param id 用户ID
  266 + * @param enabled 状态
  267 + * @return
  268 + * @Title changeEnabled
  269 + * @Description: TODO(改变用户状态)
  270 + */
  271 + @RequestMapping("/changeEnabled")
  272 + public int changeEnabled(@RequestParam int id, @RequestParam int enabled) {
  273 + return sysUserService.changeEnabled(id, enabled);
  274 + }
  275 +
  276 + /**
  277 + * @param oldPWD 原始密码
  278 + * @param newPWD 新密码
  279 + * @param cnewPWD 确认新密码
  280 + * @return
  281 + * @Title changePWD
  282 + * @Description: TODO(修改密码)
  283 + */
  284 + @RequestMapping(value = "/changePWD", method = RequestMethod.POST)
  285 + public String changePWD(@RequestParam String oldPWD, @RequestParam String newPWD, @RequestParam String cnewPWD, HttpServletRequest request) {
  286 + SysUser sysUser = SecurityUtils.getCurrentUser();
  287 + String msg = "";
  288 +
  289 + //解密RSA
  290 + try{
  291 + oldPWD = (RSAUtils.decryptBase64(oldPWD));
  292 + newPWD = (RSAUtils.decryptBase64(newPWD));
  293 + cnewPWD = (RSAUtils.decryptBase64(cnewPWD));
  294 + }catch (RuntimeException e) {
  295 + return "网络延迟,解密失败,请重新添加!";
  296 + }
  297 + if (new BCryptPasswordEncoder(4).matches(oldPWD, sysUser.getPassword())) {
  298 + if (oldPWD.equals(newPWD)) {
  299 + msg = "新密码不能跟原始密码一样!";
  300 + } else {
  301 + if (newPWD.equals(cnewPWD)) {
  302 + sysUserService.changePWD(sysUser.getId(), newPWD);
  303 + request.getSession().setAttribute(Constants.WEAK_CIPHER, 0);
  304 + msg = "修改成功!";
  305 + } else {
  306 + msg = "新密码两次输入不一致!";
  307 + }
  308 + }
  309 + } else {
  310 + msg = "原始密码错误!";
  311 + }
  312 + return msg;
  313 + }
  314 +
  315 + @RequestMapping(value = "/register", method = RequestMethod.POST)
  316 + public Map<String, Object> register(SysUser u) {
  317 + return sysUserService.register(u);
  318 + }
  319 +
  320 + // 查询用户下所有下级角色
  321 + @RequestMapping(value = "/all_distinct")
  322 + public List<SysUser> findAll_distinct() {
  323 + return sysUserService.findAll_distinct();
  324 + }
  325 +
  326 + // 重置密码
  327 + @RequestMapping(value = "/resetPassword", method = RequestMethod.POST)
  328 + public Map<String, Object> resetPassword(@RequestParam Integer id) {
  329 + return sysUserService.resetPassword(id);
  330 + }
  331 +
  332 + /**
  333 + * 解除临时锁定
  334 + * @param userName
  335 + * @return
  336 + */
  337 + @RequestMapping(value = "/unlock", method = RequestMethod.POST)
  338 + public Map<String, Object> unlock(@RequestParam String userName) {
  339 + Map<String, Object> result = new HashMap<>();
  340 + // 获取当前用户
  341 + SysUser user = SecurityUtils.getCurrentUser();
  342 + Iterator<Role> itRole = user.getRoles().iterator();
  343 + Role ro = new Role();
  344 + boolean isSuper = false;
  345 + while (itRole.hasNext()) {//判断是否有下一个
  346 + ro = itRole.next();
  347 + if (ro.getLevel() == 1) {
  348 + isSuper = true;
  349 + }
  350 + }
  351 + if (isSuper) {
  352 + USER_LOCKTIME.remove(userName);
  353 + USER_ERRTIMES.remove(userName);
  354 + result.put("status", ResponseCode.SUCCESS);
  355 + result.put("msg", "用户解锁成功!");
  356 + } else {
  357 + result.put("status", ResponseCode.ERROR);
  358 + result.put("msg", "您不是管理员无用户解锁权限");
  359 + }
  360 +
  361 + return result;
  362 + }
  363 +
  364 + /**
  365 + * 解除临时锁定
  366 + * @param request
  367 + * @return
  368 + */
  369 + @RequestMapping(value = "/isWeakCipher", method = RequestMethod.POST)
  370 + public Map<String, Object> isWeakCipher(HttpServletRequest request) {
  371 + Map<String, Object> result = new HashMap<>();
  372 + result.put("status", ResponseCode.SUCCESS);
  373 + result.put("data", request.getSession().getAttribute(Constants.WEAK_CIPHER));
  374 +
  375 + return result;
  376 + }
  377 +
  378 +}
... ...
src/main/java/com/bsth/entity/sys/SysUser.java
1 1 package com.bsth.entity.sys;
2 2  
  3 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 4 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 5  
5 6 import javax.persistence.*;
... ... @@ -25,13 +26,16 @@ public class SysUser implements Serializable {
25 26 private String userName;
26 27  
27 28 private String name;
28   -
  29 +
  30 + @JsonIgnore
29 31 private String password;
30 32  
31 33 @Column(updatable = false, name = "create_date", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
32 34 private Date createDate;
  35 +
  36 + @Column(name = "update_date", columnDefinition = "timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
  37 + private Date updateDate;
33 38  
34   - @Column(name = "last_loginDate", columnDefinition = "timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
35 39 private Date lastLoginDate;
36 40  
37 41 private String agencies;
... ... @@ -74,6 +78,14 @@ public class SysUser implements Serializable {
74 78 this.createDate = createDate;
75 79 }
76 80  
  81 + public Date getUpdateDate() {
  82 + return updateDate;
  83 + }
  84 +
  85 + public void setUpdateDate(Date updateDate) {
  86 + this.updateDate = updateDate;
  87 + }
  88 +
77 89 public Date getLastLoginDate() {
78 90 return lastLoginDate;
79 91 }
... ...
src/main/java/com/bsth/repository/sys/SysUserRepository.java
1   -package com.bsth.repository.sys;
2   -
3   -import com.bsth.entity.sys.SysUser;
4   -import com.bsth.repository.BaseRepository;
5   -import org.springframework.data.jpa.repository.EntityGraph;
6   -import org.springframework.data.jpa.repository.Modifying;
7   -import org.springframework.data.jpa.repository.Query;
8   -import org.springframework.stereotype.Repository;
9   -import org.springframework.transaction.annotation.Transactional;
10   -
11   -import java.util.List;
12   -
13   -@Repository
14   -public interface SysUserRepository extends BaseRepository<SysUser, Integer>{
15   -
16   - SysUser findByUserName(String userName);
17   -
18   - @Transactional
19   - @Modifying
20   - @Query(value="update bsth_c_sys_user set enabled=?2 where id=?1",nativeQuery=true)
21   - int changeEnabled(int id,int enabled);
22   -
23   - @Transactional
24   - @Modifying
25   - @Query(value="update bsth_c_sys_user set password=?2 where id=?1",nativeQuery=true)
26   - int changePWD(int id,String newPWD);
27   -
28   - @EntityGraph(value = "sysUser_role", type = EntityGraph.EntityGraphType.FETCH)
29   - @Query(value = "select DISTINCT u from SysUser u")
30   - List<SysUser> findAll_distinct();
31   -}
  1 +package com.bsth.repository.sys;
  2 +
  3 +import com.bsth.entity.sys.SysUser;
  4 +import com.bsth.repository.BaseRepository;
  5 +import org.springframework.data.jpa.repository.EntityGraph;
  6 +import org.springframework.data.jpa.repository.Modifying;
  7 +import org.springframework.data.jpa.repository.Query;
  8 +import org.springframework.stereotype.Repository;
  9 +import org.springframework.transaction.annotation.Transactional;
  10 +
  11 +import java.util.List;
  12 +
  13 +@Repository
  14 +public interface SysUserRepository extends BaseRepository<SysUser, Integer>{
  15 +
  16 + SysUser findByUserName(String userName);
  17 +
  18 + @Transactional
  19 + @Modifying
  20 + @Query(value="update bsth_c_sys_user set enabled=?2 where id=?1",nativeQuery=true)
  21 + int changeEnabled(int id,int enabled);
  22 +
  23 + @Transactional
  24 + @Modifying
  25 + @Query(value="update bsth_c_sys_user set password=?2 where id=?1",nativeQuery=true)
  26 + int changePWD(int id,String newPWD);
  27 +
  28 + @EntityGraph(value = "sysUser_role", type = EntityGraph.EntityGraphType.FETCH)
  29 + @Query(value = "select DISTINCT u from SysUser u")
  30 + List<SysUser> findAll_distinct();
  31 +
  32 + @Modifying
  33 + @Query(value="update bsth_c_sys_user set last_login_date=now() where user_name=?1",nativeQuery=true)
  34 + void recordLoginDate(String userName);
  35 +}
... ...
src/main/java/com/bsth/service/sys/SysUserService.java
1   -package com.bsth.service.sys;
2   -
3   -import com.bsth.entity.sys.SysUser;
4   -import com.bsth.service.BaseService;
5   -import org.springframework.web.bind.annotation.RequestParam;
6   -
7   -import java.util.List;
8   -import java.util.Map;
9   -
10   -public interface SysUserService extends BaseService<SysUser, Integer>{
11   -
12   - SysUser findByUserName(String name);
13   -
14   - int changeEnabled(int id,int enabled);
15   -
16   - int changePWD(int id,String newPWD);
17   -
18   - Map<String,Object> register(SysUser u);
19   -
20   - List<SysUser> findAll_distinct();
21   -
22   - Map<String, Object> resetPassword(@RequestParam Integer id);
23   -}
  1 +package com.bsth.service.sys;
  2 +
  3 +import com.bsth.entity.sys.SysUser;
  4 +import com.bsth.service.BaseService;
  5 +import org.springframework.web.bind.annotation.RequestParam;
  6 +
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +public interface SysUserService extends BaseService<SysUser, Integer>{
  11 +
  12 + SysUser findByUserName(String name);
  13 +
  14 + int changeEnabled(int id,int enabled);
  15 +
  16 + int changePWD(int id,String newPWD);
  17 +
  18 + Map<String,Object> register(SysUser u);
  19 +
  20 + List<SysUser> findAll_distinct();
  21 +
  22 + Map<String, Object> resetPassword(@RequestParam Integer id);
  23 +
  24 + void recordLoginDate(String userName);
  25 +}
... ...
src/main/java/com/bsth/service/sys/impl/SysUserServiceImpl.java
... ... @@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory;
20 20 import org.springframework.beans.factory.annotation.Autowired;
21 21 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
22 22 import org.springframework.stereotype.Service;
  23 +import org.springframework.transaction.annotation.Transactional;
23 24 import org.springframework.web.bind.annotation.RequestParam;
24 25  
25 26 import java.util.ArrayList;
... ... @@ -186,7 +187,7 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
186 187 rs.put("msg", "密码重置成功!");
187 188 }else {
188 189 rs.put("status", ResponseCode.ERROR);
189   - rs.put("msg", "您不是超级管理员无权限重置其他用户密码");
  190 + rs.put("msg", "您不是管理员无权限重置其他用户密码");
190 191 }
191 192 }catch (Exception e){
192 193 logger.error("", e);
... ... @@ -195,4 +196,10 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
195 196 }
196 197 return rs;
197 198 }
  199 +
  200 + @Override
  201 + @Transactional(rollbackFor = Exception.class)
  202 + public void recordLoginDate(String userName) {
  203 + sysUserRepository.recordLoginDate(userName);
  204 + }
198 205 }
... ...
src/main/resources/static/index.html
... ... @@ -431,6 +431,29 @@
431 431 });
432 432  
433 433 $(function () {
  434 + $.ajax({
  435 + url: '/user/isWeakCipher',
  436 + type: 'POST',
  437 + async: false,
  438 + success: function (result,status,xhr) {
  439 + if (result.data == 1) {
  440 + $.get('/pages/permission/user/forceChangePWD.html', function (content) {
  441 + layer.open({
  442 + type: 1,
  443 + area: ['600px', '360px'],
  444 + content: content,
  445 + title: '修改密码',
  446 + shift: 5,
  447 + scrollbar: false,
  448 + closeBtn: 0,
  449 + success: function () {
  450 + }
  451 + });
  452 + });
  453 + }
  454 + }
  455 + });
  456 +
434 457 $.get('/user/currentUser', function (user) {
435 458 $('#indexTopUName').text(user.userName);
436 459 });
... ...
src/main/resources/static/login.html
1   -<!DOCTYPE html>
2   -<html lang="zh">
3   -<head>
4   - <meta name="renderer" content="webkit" />
5   - <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
6   - <meta charset="utf-8" />
7   - <title>登录</title>
8   - <link
9   - href="/metronic_v4.5.4/plugins/font-awesome/css/font-awesome.min.css"
10   - rel="stylesheet" type="text/css" />
11   - <!-- Bootstrap style -->
12   - <link href="/metronic_v4.5.4/plugins/bootstrap/css/bootstrap.min.css"
13   - rel="stylesheet" type="text/css" />
14   -
15   - <!-- METRONIC style -->
16   - <link href="/metronic_v4.5.4/css/components.css" rel="stylesheet"
17   - type="text/css" />
18   -
19   - <style type="text/css">
20   - body>.wrapper {
21   - background-image: url(/assets/img/bg_9b9dcb65ff.png);
22   - background-size: 100px;
23   - background-repeat: repeat;
24   - min-height: 800px;
25   - min-width: 630px;
26   - position: absolute;
27   - top: 0;
28   - bottom: 0;
29   - left: 0;
30   - right: 0;
31   - }
32   -
33   - #loginPanel.dialog-shadow {
34   - width: 450px;
35   - /* height: 400px; */
36   - border: 1px solid #dadada;
37   - border-radius: 10px !important;
38   - position: absolute;
39   - box-shadow: 0 9px 30px -6px rgba(0, 0, 0, .2), 0 18px 20px -10px
40   - rgba(0, 0, 0, .04), 0 18px 20px -10px rgba(0, 0, 0, .04), 0 10px 20px
41   - -10px rgba(0, 0, 0, .04);
42   - background: url(/assets/img/dialog-gray-bg_42c40b3eb6.png) #fff bottom
43   - repeat-x;
44   - top: 50%;
45   - left: 50%;
46   - margin-left: -225px;
47   - margin-top: -300px;
48   - text-align: center;
49   - color: #333;
50   - opacity: .5;
51   -
52   - padding-bottom: 56px;
53   -
54   - animation: to_center 1s forwards;
55   - animation-delay: .2s;
56   -
57   - transition: all .3s ease;
58   - }
59   -
60   - @keyframes to_center
61   - {
62   - 0% {margin-top: -300px;opacity: .5;}
63   - 100% {margin-top: -270px;opacity: 1;}
64   - }
65   -
66   -
67   - h3 {
68   - font-size: 25px;
69   - font-weight: 600;
70   - color: #4a4a4a
71   - }
72   -
73   - .input-icon input {
74   - height: 48px;
75   - border-radius: 5px !important;
76   - transition: all .5s ease;
77   - }
78   -
79   - .input-icon input:FOCUS {
80   - border-color: #c2cad8;
81   - box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) !important;
82   - }
83   -
84   - .input-icon>i {
85   - margin-top: 16px;
86   - }
87   -
88   - #loginPanel #loginBtn.btn{
89   - border-radius: 6px !important;
90   - width: 378px;
91   - height: 48px;
92   - font-size: 20px;
93   - font-family: 微软雅黑;
94   - transition: all .3s ease;
95   -
96   - background: #5f7ed7;
97   - background: linear-gradient(#6f97e5,#527ed9);
98   - box-shadow: inset 0 1px 2px #7ea1e8 !important;
99   - color: #fff;
100   - text-shadow: #4f70b3 0 -1px 0;
101   - border: none;
102   - }
103   -
104   - #loginPanel #loginBtn.btn:HOVER {
105   - box-shadow: inset 0 1px 1px #7696de,inset 0 0 2px #627dca,inset 0 -2px 3px #5a77c7,inset 0 0 100px rgba(48,77,147,.4) !important;
106   - }
107   -
108   -
109   - #loginPanel.show_msg{
110   - top: calc(50% - 10px);
111   - }
112   -
113   - #loginPanel .alert{
114   - display: none;
115   - padding: 12px;
116   - margin-top: 21px;
117   - border-radius: 0 0 10px 10px !important;
118   - font-size: 13px;
119   -
120   - position: absolute;
121   - width: 100%;
122   - border-bottom: 1px solid #dadada;
123   - }
124   -
125   - #loginPanel .alert.login-success{
126   - color: #27a4b0;
127   - background: #abe7ed;
128   - border-color: #abe7ed;
129   - }
130   -
131   - #loginPanel .alert i{
132   - font-size: 16px;
133   - vertical-align: middle;
134   - margin: 0 5px 3px;
135   - }
136   -
137   - #loginPanel.show_msg .alert{
138   - display: block;
139   - }
140   -
141   - #captchaWrap{
142   - display: none;
143   - text-align: left;
144   - border-top: 1px solid #f3f2f2;
145   - }
146   -
147   - img.captcha-img{
148   - cursor: pointer;
149   - }
150   -
151   - .login-footer{
152   - position: fixed;
153   - width: 100%;
154   - bottom: 35px;
155   - text-align: center;
156   - color: #a6a6a6;
157   - }
158   -
159   - h3.logo-text{
160   - font-family: 华文楷体,华文细黑;
161   - font-size: 28px;
162   - }
163   -
164   - .warn-note{
165   - width: 100%;
166   - position: absolute;
167   - top: 0;
168   - z-index: 2;
169   - text-align: center;
170   - background: #ff4646;
171   - color: white;
172   - padding: 12px;
173   - display: none;
174   - }
175   - </style>
176   -</head>
177   -
178   -<body>
179   -<div class="warn-note">警告!系统目前仅在 WebKit 内核下完成兼容性测试,请使用 Google
180   - Chrome 浏览器进入系统。</div>
181   -<div class="wrapper ng-scope">
182   - <div id="loginPanel" class="dialog dialog-shadow">
183   - <br>
184   - <h3 class="logo-text">浦东公交调度系统</h3>
185   - <hr>
186   - <form style="padding: 0px 35px;">
187   - <div class="form-group" style="margin-bottom: 0">
188   - <label></label>
189   - <div class="input-icon">
190   - <i class="fa fa-user font-gray"></i> <input type="text"
191   - name="userName" class="form-control" placeholder="输入用户名"
192   - autofocus="autofocus" autocomplete="off">
193   - </div>
194   - </div>
195   -
196   - <div class="form-group">
197   - <label></label>
198   - <div class="input-icon">
199   - <i class="fa fa-key font-gray"></i> <input type="password"
200   - name="password" class="form-control" placeholder="输入密码">
201   - </div>
202   - </div>
203   -
204   - <div class="form-group" id="captchaWrap">
205   - <label></label>
206   - <div class="input-icon">
207   - <input type="text" name="captcha" style="width: 153px !important;"
208   - class="form-control input-inline input-medium"
209   - placeholder="输入验证码"> <span class="help-inline"> <img
210   - alt="验证码" class="captcha-img" title="点击刷新验证码">
211   - </span>
212   - </div>
213   - </div>
214   - </form>
215   - <br>
216   - <br>
217   - <div class="form-actions">
218   - <button class="btn blue-steel" id="loginBtn" disabled="disabled">登录</button>
219   - </div>
220   -
221   - <div class="alert alert-danger"></div>
222   - </div>
223   -
224   - <div class="login-footer">© 2016 上海巴士拓华科技发展有限公司 Some Rights
225   - Reserved</div>
226   -</div>
227   -
228   -<script>
229   - delete window.require;
230   - delete window.exports;
231   - delete window.module;
232   -</script>
233   -<!-- jQuery -->
234   -<script src="/metronic_v4.5.4/plugins/jquery.min.js"></script>
235   -<script src="/assets/plugins/jsencrypt.min.js"></script>
236   -<script>
237   - window.onload=function(){
238   - var body=document.getElementsByTagName("body")[0];
239   - if(typeof body.style.WebkitAnimation=="undefined")
240   - $('.warn-note').fadeIn();
241   - };
242   - !function(){
243   - var form = $('#loginPanel form')
244   - ,nameInput = $('input[name=userName]', form)
245   - ,pwdInput = $('input[name=password]', form)
246   - ,msgAlert = $('#loginPanel .alert-danger');
247   -
248   - $('input', form).on('keyup', checkBtnStatus);
249   -
250   - var keys;
251   - $.get('/user/login/jCryptionKey?t='+Math.random(), function(data){
252   - keys = data.publickey;
253   - });
254   -
255   -
256   -
257   - function checkBtnStatus(){
258   - var es = $('input:visible', form);
259   - for(var i = 0, e; e = es[i++];){
260   - if($.trim($(e).val()) == ''){
261   - $('#loginBtn').attr('disabled', 'disabled');
262   - $('#loginPanel').removeClass('show_msg');
263   - return;
264   - }
265   - }
266   - $('#loginBtn').removeAttr('disabled');
267   - }
268   -
269   - nameInput.on('blur', checkStatus);
270   - //keyup 事件做延迟
271   - var uNameKeyup;
272   - nameInput.on('keyup', function(){
273   - if(uNameKeyup)
274   - return;
275   - uNameKeyup = true;
276   - setTimeout(function(){
277   - checkStatus();
278   - uNameKeyup = false;
279   - }, 200);
280   - });
281   -
282   - //密码框回车事件
283   - pwdInput.on('keyup', function(e){
284   - if (e.keyCode == 13)
285   - $('#loginBtn').click();
286   - });
287   - //验证码框回车事件
288   - $('input[name=captcha]').on('keyup', function(e){
289   - if (e.keyCode == 13)
290   - $('#loginBtn').click();
291   - });
292   -
293   - $('#loginBtn').on('click', function(){
294   - if(lock || $(this).attr('disabled')) return;
295   - var userName = nameInput.val()
296   - ,pwd = pwdInput.val();
297   -
298   - //RSA加密
299   - var encrypt = new JSEncrypt();
300   - encrypt.setPublicKey(keys);
301   - userName = encrypt.encrypt(userName);
302   - pwd = encrypt.encrypt(pwd);
303   - //登录
304   - login(userName, pwd);
305   - });
306   -
307   - var lock;
308   - function login(userName, pwd){
309   - lock = true;
310   - $('#loginBtn').attr('disabled', 'disabled');
311   -
312   - var params = {
313   - userName: userName,
314   - password: pwd,
315   - captcha: $('input[name=captcha]').val()
316   - };
317   - $.post('/user/login', params
318   - ,function(rs){
319   -
320   - $('#loginPanel').addClass('show_msg');
321   - if(error(rs)){
322   - lock = false;
323   - $('#loginBtn').removeAttr('disabled');
324   -
325   - msgAlert.html('<i class="fa fa-times-circle"> </i> 登录失败,' + rs.msg);
326   -
327   - _captcha.refresh();
328   - checkStatus();
329   - }
330   - else{
331   - msgAlert.html('<i class="fa fa-check"> </i> 登录成功!');
332   - msgAlert.addClass('login-success');
333   - window.location.href = '/';
334   - }
335   - });
336   - }
337   -
338   - function checkStatus(){
339   - var t = nameInput.val();
340   - if(!t){
341   - hide();
342   - return;
343   - }
344   -
345   - $.get('/user/login/captchaStatus', {userName: t}, function(rs){
346   - if(rs >= 3)
347   - _captcha.show();
348   - else
349   - hide();
350   - });
351   -
352   - function hide(){
353   - if(!$("#captchaWrap").is(":hidden")){
354   - _captcha.hide();
355   - //隐藏提示消息
356   - msgAlert.html('');
357   - $('#loginPanel').removeClass('show_msg');
358   - }
359   - }
360   - }
361   -
362   -
363   - var _captcha = {
364   - show: function(){
365   - if($("#captchaWrap").is(":hidden")){
366   - $('#captchaWrap').fadeIn(500);
367   - _captcha.refresh();
368   - checkBtnStatus();
369   - }
370   - },
371   - refresh: function(){
372   - if($("#captchaWrap").is(":hidden"))
373   - return;
374   - $('#captchaWrap img.captcha-img').attr('src', '/captcha.jpg?t=' + Math.random());
375   - },
376   - hide: function(){
377   - $('#captchaWrap').hide();
378   - $('input[name=captcha]').val('');
379   - }
380   - };
381   -
382   - $('#captchaWrap img.captcha-img').on('click', function(){
383   - $(this).attr('src', '/captcha.jpg?t=' + Math.random());
384   - });
385   -
386   - function error(rs){
387   - return rs.status == 'ERROR' || rs.status == 500;
388   - }
389   - }();
390   -</script>
391   -</body>
  1 +<!DOCTYPE html>
  2 +<html lang="zh">
  3 +<head>
  4 + <meta name="renderer" content="webkit" />
  5 + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  6 + <meta charset="utf-8" />
  7 + <title>登录</title>
  8 + <link
  9 + href="/metronic_v4.5.4/plugins/font-awesome/css/font-awesome.min.css"
  10 + rel="stylesheet" type="text/css" />
  11 + <!-- Bootstrap style -->
  12 + <link href="/metronic_v4.5.4/plugins/bootstrap/css/bootstrap.min.css"
  13 + rel="stylesheet" type="text/css" />
  14 +
  15 + <!-- METRONIC style -->
  16 + <link href="/metronic_v4.5.4/css/components.css" rel="stylesheet"
  17 + type="text/css" />
  18 +
  19 + <style type="text/css">
  20 + body>.wrapper {
  21 + background-image: url(/assets/img/bg_9b9dcb65ff.png);
  22 + background-size: 100px;
  23 + background-repeat: repeat;
  24 + min-height: 800px;
  25 + min-width: 630px;
  26 + position: absolute;
  27 + top: 0;
  28 + bottom: 0;
  29 + left: 0;
  30 + right: 0;
  31 + }
  32 +
  33 + #loginPanel.dialog-shadow {
  34 + width: 450px;
  35 + /* height: 400px; */
  36 + border: 1px solid #dadada;
  37 + border-radius: 10px !important;
  38 + position: absolute;
  39 + box-shadow: 0 9px 30px -6px rgba(0, 0, 0, .2), 0 18px 20px -10px
  40 + rgba(0, 0, 0, .04), 0 18px 20px -10px rgba(0, 0, 0, .04), 0 10px 20px
  41 + -10px rgba(0, 0, 0, .04);
  42 + background: url(/assets/img/dialog-gray-bg_42c40b3eb6.png) #fff bottom
  43 + repeat-x;
  44 + top: 50%;
  45 + left: 50%;
  46 + margin-left: -225px;
  47 + margin-top: -300px;
  48 + text-align: center;
  49 + color: #333;
  50 + opacity: .5;
  51 +
  52 + padding-bottom: 56px;
  53 +
  54 + animation: to_center 1s forwards;
  55 + animation-delay: .2s;
  56 +
  57 + transition: all .3s ease;
  58 + }
  59 +
  60 + @keyframes to_center
  61 + {
  62 + 0% {margin-top: -300px;opacity: .5;}
  63 + 100% {margin-top: -270px;opacity: 1;}
  64 + }
  65 +
  66 +
  67 + h3 {
  68 + font-size: 25px;
  69 + font-weight: 600;
  70 + color: #4a4a4a
  71 + }
  72 +
  73 + .input-icon input {
  74 + height: 48px;
  75 + border-radius: 5px !important;
  76 + transition: all .5s ease;
  77 + }
  78 +
  79 + .input-icon input:FOCUS {
  80 + border-color: #c2cad8;
  81 + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) !important;
  82 + }
  83 +
  84 + .input-icon>i {
  85 + margin-top: 16px;
  86 + }
  87 +
  88 + #loginPanel #loginBtn.btn{
  89 + border-radius: 6px !important;
  90 + width: 378px;
  91 + height: 48px;
  92 + font-size: 20px;
  93 + font-family: 微软雅黑;
  94 + transition: all .3s ease;
  95 +
  96 + background: #5f7ed7;
  97 + background: linear-gradient(#6f97e5,#527ed9);
  98 + box-shadow: inset 0 1px 2px #7ea1e8 !important;
  99 + color: #fff;
  100 + text-shadow: #4f70b3 0 -1px 0;
  101 + border: none;
  102 + }
  103 +
  104 + #loginPanel #loginBtn.btn:HOVER {
  105 + box-shadow: inset 0 1px 1px #7696de,inset 0 0 2px #627dca,inset 0 -2px 3px #5a77c7,inset 0 0 100px rgba(48,77,147,.4) !important;
  106 + }
  107 +
  108 +
  109 + #loginPanel.show_msg{
  110 + top: calc(50% - 10px);
  111 + }
  112 +
  113 + #loginPanel .alert{
  114 + display: none;
  115 + padding: 12px;
  116 + margin-top: 21px;
  117 + border-radius: 0 0 10px 10px !important;
  118 + font-size: 13px;
  119 +
  120 + position: absolute;
  121 + width: 100%;
  122 + border-bottom: 1px solid #dadada;
  123 + }
  124 +
  125 + #loginPanel .alert.login-success{
  126 + color: #27a4b0;
  127 + background: #abe7ed;
  128 + border-color: #abe7ed;
  129 + }
  130 +
  131 + #loginPanel .alert i{
  132 + font-size: 16px;
  133 + vertical-align: middle;
  134 + margin: 0 5px 3px;
  135 + }
  136 +
  137 + #loginPanel.show_msg .alert{
  138 + display: block;
  139 + }
  140 +
  141 + #captchaWrap{
  142 + display: none;
  143 + text-align: left;
  144 + border-top: 1px solid #f3f2f2;
  145 + }
  146 +
  147 + img.captcha-img{
  148 + cursor: pointer;
  149 + }
  150 +
  151 + .login-footer{
  152 + position: fixed;
  153 + width: 100%;
  154 + bottom: 35px;
  155 + text-align: center;
  156 + color: #a6a6a6;
  157 + }
  158 +
  159 + h3.logo-text{
  160 + font-family: 华文楷体,华文细黑;
  161 + font-size: 28px;
  162 + }
  163 +
  164 + .warn-note{
  165 + width: 100%;
  166 + position: absolute;
  167 + top: 0;
  168 + z-index: 2;
  169 + text-align: center;
  170 + background: #ff4646;
  171 + color: white;
  172 + padding: 12px;
  173 + display: none;
  174 + }
  175 + </style>
  176 +</head>
  177 +
  178 +<body>
  179 +<div class="warn-note">警告!系统目前仅在 WebKit 内核下完成兼容性测试,请使用 Google
  180 + Chrome 浏览器进入系统。</div>
  181 +<div class="wrapper ng-scope">
  182 + <div id="loginPanel" class="dialog dialog-shadow">
  183 + <br>
  184 + <h3 class="logo-text">浦东公交调度系统</h3>
  185 + <hr>
  186 + <form style="padding: 0px 35px;">
  187 + <div class="form-group" style="margin-bottom: 0">
  188 + <label></label>
  189 + <div class="input-icon">
  190 + <i class="fa fa-user font-gray"></i> <input type="text"
  191 + name="userName" class="form-control" placeholder="输入用户名"
  192 + autofocus="autofocus" autocomplete="off">
  193 + </div>
  194 + </div>
  195 +
  196 + <div class="form-group">
  197 + <label></label>
  198 + <div class="input-icon">
  199 + <i class="fa fa-key font-gray"></i> <input type="password"
  200 + name="password" class="form-control" placeholder="输入密码">
  201 + </div>
  202 + </div>
  203 +
  204 + <div class="form-group" id="captchaWrap">
  205 + <label></label>
  206 + <div class="input-icon">
  207 + <input type="text" name="captcha" style="width: 153px !important;"
  208 + class="form-control input-inline input-medium"
  209 + placeholder="输入验证码"> <span class="help-inline"> <img
  210 + alt="验证码" class="captcha-img" title="点击刷新验证码">
  211 + </span>
  212 + </div>
  213 + </div>
  214 + </form>
  215 + <br>
  216 + <br>
  217 + <div class="form-actions">
  218 + <button class="btn blue-steel" id="loginBtn" disabled="disabled">登录</button>
  219 + </div>
  220 +
  221 + <div class="alert alert-danger"></div>
  222 + </div>
  223 +
  224 + <div class="login-footer">© 2016 上海巴士拓华科技发展有限公司 Some Rights
  225 + Reserved</div>
  226 +</div>
  227 +
  228 +<script>
  229 + delete window.require;
  230 + delete window.exports;
  231 + delete window.module;
  232 +</script>
  233 +<!-- jQuery -->
  234 +<script src="/metronic_v4.5.4/plugins/jquery.min.js"></script>
  235 +<script src="/assets/plugins/jsencrypt.min.js"></script>
  236 +<script>
  237 + window.onload=function(){
  238 + var body=document.getElementsByTagName("body")[0];
  239 + if(typeof body.style.WebkitAnimation=="undefined")
  240 + $('.warn-note').fadeIn();
  241 + };
  242 + !function(){
  243 + var form = $('#loginPanel form')
  244 + ,nameInput = $('input[name=userName]', form)
  245 + ,pwdInput = $('input[name=password]', form)
  246 + ,msgAlert = $('#loginPanel .alert-danger');
  247 +
  248 + $('input', form).on('keyup', checkBtnStatus);
  249 +
  250 + var keys;
  251 + $.get('/user/login/jCryptionKey?t='+Math.random(), function(data){
  252 + keys = data.publickey;
  253 + });
  254 +
  255 +
  256 +
  257 + function checkBtnStatus(){
  258 + var es = $('input:visible', form);
  259 + for(var i = 0, e; e = es[i++];){
  260 + if($.trim($(e).val()) == ''){
  261 + $('#loginBtn').attr('disabled', 'disabled');
  262 + $('#loginPanel').removeClass('show_msg');
  263 + return;
  264 + }
  265 + }
  266 + $('#loginBtn').removeAttr('disabled');
  267 + }
  268 +
  269 + nameInput.on('blur', checkStatus);
  270 + //keyup 事件做延迟
  271 + var uNameKeyup;
  272 + nameInput.on('keyup', function(){
  273 + if(uNameKeyup)
  274 + return;
  275 + uNameKeyup = true;
  276 + setTimeout(function(){
  277 + checkStatus();
  278 + uNameKeyup = false;
  279 + }, 200);
  280 + });
  281 +
  282 + //密码框回车事件
  283 + pwdInput.on('keyup', function(e){
  284 + if (e.keyCode == 13)
  285 + $('#loginBtn').click();
  286 + });
  287 + //验证码框回车事件
  288 + $('input[name=captcha]').on('keyup', function(e){
  289 + if (e.keyCode == 13)
  290 + $('#loginBtn').click();
  291 + });
  292 +
  293 + $('#loginBtn').on('click', function(){
  294 + if(lock || $(this).attr('disabled')) return;
  295 + var userName = nameInput.val()
  296 + ,pwd = pwdInput.val();
  297 +
  298 + //RSA加密
  299 + var encrypt = new JSEncrypt();
  300 + encrypt.setPublicKey(keys);
  301 + userName = encrypt.encrypt(userName);
  302 + pwd = encrypt.encrypt(pwd);
  303 + //登录
  304 + login(userName, pwd);
  305 + });
  306 +
  307 + var lock;
  308 + function login(userName, pwd){
  309 + lock = true;
  310 + $('#loginBtn').attr('disabled', 'disabled');
  311 +
  312 + var params = {
  313 + userName: userName,
  314 + password: pwd,
  315 + captcha: $('input[name=captcha]').val()
  316 + };
  317 + $.post('/user/login', params
  318 + ,function(rs){
  319 +
  320 + $('#loginPanel').addClass('show_msg');
  321 + if(error(rs)){
  322 + lock = false;
  323 + $('#loginBtn').removeAttr('disabled');
  324 + msgAlert.html('<i class="fa fa-times-circle"> </i> 登录失败,' + rs.msg);
  325 +
  326 + _captcha.refresh();
  327 + checkStatus();
  328 + }
  329 + else{
  330 + msgAlert.html('<i class="fa fa-check"> </i> 登录成功!');
  331 + msgAlert.addClass('login-success');
  332 + window.location.href = '/';
  333 + }
  334 + });
  335 + }
  336 +
  337 + function checkStatus(){
  338 + var t = nameInput.val();
  339 + if(!t){
  340 + hide();
  341 + return;
  342 + }
  343 +
  344 + $.get('/user/login/captchaStatus', {userName: t}, function(rs){
  345 + if(rs > 1)
  346 + _captcha.show();
  347 + else
  348 + hide();
  349 + });
  350 +
  351 + function hide(){
  352 + if(!$("#captchaWrap").is(":hidden")){
  353 + _captcha.hide();
  354 + //隐藏提示消息
  355 + //msgAlert.html('');
  356 + //$('#loginPanel').removeClass('show_msg');
  357 + }
  358 + }
  359 + }
  360 +
  361 +
  362 + var _captcha = {
  363 + show: function(){
  364 + if($("#captchaWrap").is(":hidden")){
  365 + $('#captchaWrap').fadeIn(500);
  366 + _captcha.refresh();
  367 + checkBtnStatus();
  368 + }
  369 + },
  370 + refresh: function(){
  371 + if($("#captchaWrap").is(":hidden"))
  372 + return;
  373 + $('#captchaWrap img.captcha-img').attr('src', '/captcha.jpg?t=' + Math.random());
  374 + },
  375 + hide: function(){
  376 + $('#captchaWrap').hide();
  377 + $('input[name=captcha]').val('');
  378 + }
  379 + };
  380 +
  381 + $('#captchaWrap img.captcha-img').on('click', function(){
  382 + $(this).attr('src', '/captcha.jpg?t=' + Math.random());
  383 + });
  384 +
  385 + function error(rs){
  386 + return rs.status == 'ERROR' || rs.status == 500;
  387 + }
  388 + }();
  389 +</script>
  390 +</body>
392 391 </html>
393 392 \ No newline at end of file
... ...
src/main/resources/static/pages/permission/user/changePWD.html
... ... @@ -54,11 +54,27 @@ $(function(){
54 54 //表单 validate
55 55 var error = $('.alert-danger', form);
56 56  
  57 + var validate = function (pwd) {
  58 + var flag = true;
  59 + for (var i = 1; i < pwd.length - 1; i++) {
  60 + var first = pwd.charCodeAt(i - 1);
  61 + var second = pwd.charCodeAt(i);
  62 + var third = pwd.charCodeAt(i + 1);
  63 + if (!(first >= 48 && third <= 57 || first >= 65 && third <= 90 || first >= 97 && third <= 122)) {
  64 + continue;
  65 + }
  66 + if (third - second == 1 && second - first == 1) {
  67 + flag = false;
  68 + }
  69 + }
  70 +
  71 + return flag;
  72 + }
  73 +
57 74 $.validator.addMethod("passwordrule", function(value, element) {
58 75 var reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*?[#?!@$%^&*-.]).{8,16}$/;
59   - // var reg = /^(?=.*[a-zA-Z])(?=.*\d).{8,16}$/;
60   - return this.optional(element) ||(reg.test(value));
61   - }, "需包含大小写字母、数字、以及特殊符号的8-16位字符");
  76 + return this.optional(element) || reg.test(value) && validate(value);
  77 + }, "需包含大小写字母、数字、以及特殊符号的8-16位字符,并不能有123、abc这样的连续字符");
62 78  
63 79 //表单 validate
64 80 form.validate({
... ...
src/main/resources/static/pages/permission/user/forceChangePWD.html
1 1 <div class="row">
2   -<div class="col-md-12">
3   -<!-- BEGIN VALIDATION STATES-->
4   -<div class="portlet light portlet-fit portlet-form bordered">
5   -<div class="portlet-body">
6   - <form class="form-horizontal" id="forceChangePWDForm">
7   - <div class="alert alert-danger display-hide">
8   - <button class="close" data-close="alert"></button>您的输入有误,请检查下面的输入项
9   - </div>
10   - <div class="form-group" style="margin-top: 60px">
11   - <label class="control-label col-md-5">原始密码:
12   - </label>
13   - <div class="col-md-4">
14   - <div class="input-icon right">
15   - <i class="fa"></i>
16   - <input type="password" class="form-control" name="oldPWD" /> </div>
17   - </div>
  2 + <div class="col-md-12">
  3 + <!-- BEGIN VALIDATION STATES-->
  4 + <div class="portlet light portlet-fit portlet-form bordered">
  5 + <div class="portlet-body">
  6 + <form class="form-horizontal" id="forceChangePWDForm">
  7 + <div class="alert alert-danger display-hide">
  8 + <button class="close" data-close="alert"></button>您的输入有误,请检查下面的输入项
  9 + </div>
  10 + <div class="form-group" style="margin-top: 60px">
  11 + <label class="control-label col-md-5">原始密码:
  12 + </label>
  13 + <div class="col-md-4">
  14 + <div class="input-icon right">
  15 + <i class="fa"></i>
  16 + <input type="password" class="form-control" name="oldPWD" /> </div>
  17 + </div>
  18 + </div>
  19 + <div class="form-group">
  20 + <label class="control-label col-md-5">输入新密码:
  21 + </label>
  22 + <div class="col-md-4">
  23 + <div class="input-icon right">
  24 + <i class="fa"></i>
  25 + <input type="password" class="form-control" name="newPWD" id="newPWD"/> </div>
  26 + </div>
  27 + </div>
  28 + <div class="form-group">
  29 + <label class="control-label col-md-5">确认新密码:
  30 + </label>
  31 + <div class="col-md-4">
  32 + <div class="input-icon right">
  33 + <i class="fa"></i>
  34 + <input type="password" class="form-control" name="cnewPWD" /> </div>
  35 + </div>
  36 + </div>
  37 + <div class="form-actions">
  38 + <div class="row">
  39 + <div class="col-md-offset-5 col-md-7">
  40 + <button type="submit" id="confirm" class="btn green">确定</button>
  41 + </div>
  42 + </div>
  43 + </div>
  44 + </form>
  45 + </div>
18 46 </div>
19   - <div class="form-group">
20   - <label class="control-label col-md-5">输入新密码:
21   - </label>
22   - <div class="col-md-4">
23   - <div class="input-icon right">
24   - <i class="fa"></i>
25   - <input type="password" class="form-control" name="newPWD" id="newPWD"/> </div>
26   - </div>
27   - </div>
28   - <div class="form-group">
29   - <label class="control-label col-md-5">确认新密码:
30   - </label>
31   - <div class="col-md-4">
32   - <div class="input-icon right">
33   - <i class="fa"></i>
34   - <input type="password" class="form-control" name="cnewPWD" /> </div>
35   - </div>
36   - </div>
37   - <div class="form-actions">
38   - <div class="row">
39   - <div class="col-md-offset-5 col-md-7">
40   - <button type="submit" id="confirm" class="btn green">确定</button>
41   - </div>
42   - </div>
43   - </div>
44   - </form>
45   -</div>
46   -</div>
47   -</div>
  47 + </div>
48 48 </div>
49 49  
50 50 <script>
51   -$(function(){
52   - var form = $('#forceChangePWDForm');
53   - //表单 validate
54   - var error = $('.alert-danger', form);
  51 + $(function(){
  52 + var form = $('#forceChangePWDForm');
  53 + //表单 validate
  54 + var error = $('.alert-danger', form);
  55 +
  56 + var validate = function (pwd) {
  57 + var flag = true;
  58 + for (var i = 1; i < pwd.length - 1; i++) {
  59 + var first = pwd.charCodeAt(i - 1);
  60 + var second = pwd.charCodeAt(i);
  61 + var third = pwd.charCodeAt(i + 1);
  62 + if (!(first >= 48 && third <= 57 || first >= 65 && third <= 90 || first >= 97 && third <= 122)) {
  63 + continue;
  64 + }
  65 + if (third - second == 1 && second - first == 1) {
  66 + flag = false;
  67 + }
  68 + }
  69 +
  70 + return flag;
  71 + }
55 72  
56   - $.validator.addMethod("passwordrule", function(value, element) {
57   - var reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*?[#?!@$%^&*-]).{8,16}$/;
58   - //var reg = /^(?=.*[a-zA-Z])(?=.*\d).{8,16}$/;
59   - return this.optional(element) ||(reg.test(value));
60   - }, "需包含字母、数字的8-16位字符");
  73 + $.validator.addMethod("passwordrule", function(value, element) {
  74 + var reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*?[#?!@$%^&*-.]).{8,16}$/;
  75 + return this.optional(element) || reg.test(value) && validate(value);
  76 + }, "需包含大小写字母、数字、以及特殊符号的8-16位字符,并不能有123、abc这样的连续字符");
61 77  
62   - //表单 validate
63   - form.validate({
64   - errorElement : 'span',
65   - errorClass : 'help-block help-block-error',
66   - focusInvalid : false,
67   - rules : {
68   - 'newPWD' : {
69   - required : true,
70   - minlength: 8,
71   - maxlength: 16,
72   - passwordrule:true
73   - },
74   - 'cnewPWD' : {
75   - equalTo: '#newPWD'
76   - }
77   - },
78   - invalidHandler : function(event, validator) {
79   - error.show();
80   - App.scrollTo(error, -200);
81   - },
  78 + //表单 validate
  79 + form.validate({
  80 + errorElement : 'span',
  81 + errorClass : 'help-block help-block-error',
  82 + focusInvalid : false,
  83 + rules : {
  84 + 'newPWD' : {
  85 + required : true,
  86 + minlength: 6,
  87 + maxlength: 16,
  88 + passwordrule:true
  89 + },
  90 + 'cnewPWD' : {
  91 + equalTo: '#newPWD'
  92 + }
  93 + },
  94 + invalidHandler : function(event, validator) {
  95 + error.show();
  96 + App.scrollTo(error, -200);
  97 + },
82 98  
83   - highlight : function(element) {
84   - $(element).closest('.form-group').addClass('has-error');
85   - },
  99 + highlight : function(element) {
  100 + $(element).closest('.form-group').addClass('has-error');
  101 + },
86 102  
87   - unhighlight : function(element) {
88   - $(element).closest('.form-group').removeClass('has-error');
89   - },
  103 + unhighlight : function(element) {
  104 + $(element).closest('.form-group').removeClass('has-error');
  105 + },
90 106  
91   - success : function(label) {
92   - label.closest('.form-group').removeClass('has-error');
93   - },
94   -
95   - submitHandler : function(f) {
96   - var params = form.serializeJSON();
97   - error.hide();
  107 + success : function(label) {
  108 + label.closest('.form-group').removeClass('has-error');
  109 + },
98 110  
99   - var keys;
100   - $.ajax({
101   - url: "/user/login/jCryptionKey?t="+Math.random(),
102   - type: "Get",
103   - async:false,
104   - data: null,
105   - success: function(data) {
106   - keys = data.publickey;
107   - }
108   - });
109   - //RSA加密
110   - var encrypt = new JSEncrypt();
111   - encrypt.setPublicKey(keys);
112   - params.oldPWD = encrypt.encrypt(params.oldPWD);
113   - params.newPWD = encrypt.encrypt(params.newPWD);
114   - params.cnewPWD = encrypt.encrypt(params.cnewPWD);
115   - $.ajax({
116   - url: '/user/changePWD',
117   - type: 'POST',
118   - traditional: true,
119   - data: params,
120   - success: function(msg){
121   - layer.close();
122   - }
123   - });
124   - }
125   - });
126   -});
  111 + submitHandler : function(f) {
  112 + var params = form.serializeJSON();
  113 + error.hide();
  114 + var keys;
  115 + $.ajax({
  116 + url: "/user/login/jCryptionKey?t="+Math.random(),
  117 + type: "Get",
  118 + async:false,
  119 + data: null,
  120 + success: function(data) {
  121 + keys = data.publickey;
  122 + }
  123 + });
  124 + //RSA加密
  125 + var encrypt = new JSEncrypt();
  126 + encrypt.setPublicKey(keys);
  127 + params.oldPWD = encrypt.encrypt(params.oldPWD);
  128 + params.newPWD = encrypt.encrypt(params.newPWD);
  129 + params.cnewPWD = encrypt.encrypt(params.cnewPWD);
  130 + $.ajax({
  131 + url: '/user/changePWD',
  132 + type: 'POST',
  133 + traditional: true,
  134 + data: params,
  135 + success: function(msg){
  136 + layer.alert(msg);
  137 + layer.closeAll('page');
  138 + }
  139 + });
  140 + }
  141 + });
  142 + });
127 143 </script>
128 144 \ No newline at end of file
... ...
src/main/resources/static/pages/permission/user/list.html
... ... @@ -32,13 +32,13 @@
32 32 <thead>
33 33 <tr role="row" class="heading">
34 34 <th width="3%">#</th>
35   - <th width="15%">登录名</th>
36   - <th width="13%">姓名</th>
37   - <th width="100">所属机构</th>
  35 + <th width="10%">登录名</th>
  36 + <th width="10%">姓名</th>
  37 + <th width="12%">所属机构</th>
38 38 <th width="11%">角色</th>
39 39 <th width="10%">状态</th>
40 40 <th width="18%">最后登录时间</th>
41   - <th width="18%">操作</th>
  41 + <th width="26%">操作</th>
42 42 </tr>
43 43 <tr role="row" class="filter">
44 44 <td></td>
... ... @@ -120,6 +120,9 @@
120 120 {{if obj.isAdmin}}
121 121 <a class="btn btn-sm red btn-outline reset_password" data-id="{{obj.id}}" data-name="{{obj.userName}}" data-pjax><i class="fa fa-undo"></i> 重置密码</a>
122 122 {{/if}}
  123 + {{if obj.isAdmin}}
  124 + <a class="btn btn-sm red btn-outline unlock" data-name="{{obj.userName}}" data-pjax><i class="fa fa-unlock"></i> 解除锁定</a>
  125 + {{/if}}
123 126 </td>
124 127 </tr>
125 128 {{/each}}
... ... @@ -153,14 +156,14 @@ $(function(){
153 156 var id = $(this).data('id');
154 157 var name = $(this).data('name');
155 158 swal({
156   - title: "重装密码",
157   - text: "将登录名为"+name+"的用户,密码重置为随机密码!",
158   - type: "warning",
159   - showCancelButton: true,
160   - confirmButtonColor: "#DD6B55",
161   - confirmButtonText: "重置",
162   - cancelButtonText: "取消",
163   - closeOnConfirm: false },
  159 + title: "重置密码",
  160 + text: "将登录名为"+name+"的用户,密码重置为随机密码!",
  161 + type: "warning",
  162 + showCancelButton: true,
  163 + confirmButtonColor: "#DD6B55",
  164 + confirmButtonText: "重置",
  165 + cancelButtonText: "取消",
  166 + closeOnConfirm: false },
164 167 function(){
165 168 $.post('/user/resetPassword',{'id':id},function(result){
166 169 if(result.status=='SUCCESS') {
... ... @@ -175,7 +178,30 @@ $(function(){
175 178 jsDoQuery(getParams(), true);
176 179 });
177 180 });
178   - });
  181 + }).on('click', 'a.unlock', function () {
  182 + var name = $(this).data('name');
  183 + swal({
  184 + title: "解除锁定",
  185 + text: "将登录名为"+name+"的用户,锁定状态解除!",
  186 + type: "warning",
  187 + showCancelButton: true,
  188 + confirmButtonColor: "#DD6B55",
  189 + confirmButtonText: "重置",
  190 + cancelButtonText: "取消",
  191 + closeOnConfirm: false },
  192 + function(){
  193 + $.post('/user/unlock',{'userName':name},function(result){
  194 + if(result.status=='SUCCESS') {
  195 + // 弹出添加成功提示消息
  196 + swal("登录名为"+name+"的用户锁定解除成功!", "success");
  197 + } else if(result.status=='ERROR') {
  198 + // 弹出添加失败提示消息
  199 + swal("锁定解除失败!", result.msg+",请联系开发人员!", "ERROR");
  200 + }
  201 + jsDoQuery(getParams(), true);
  202 + });
  203 + });
  204 + });
179 205 jsDoQuery(null,true);
180 206  
181 207 //重置
... ...