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 package com.bsth.entity.sys; 1 package com.bsth.entity.sys;
2 2
  3 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 5
5 import javax.persistence.*; 6 import javax.persistence.*;
@@ -25,13 +26,16 @@ public class SysUser implements Serializable { @@ -25,13 +26,16 @@ public class SysUser implements Serializable {
25 private String userName; 26 private String userName;
26 27
27 private String name; 28 private String name;
28 - 29 +
  30 + @JsonIgnore
29 private String password; 31 private String password;
30 32
31 @Column(updatable = false, name = "create_date", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") 33 @Column(updatable = false, name = "create_date", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
32 private Date createDate; 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 private Date lastLoginDate; 39 private Date lastLoginDate;
36 40
37 private String agencies; 41 private String agencies;
@@ -74,6 +78,14 @@ public class SysUser implements Serializable { @@ -74,6 +78,14 @@ public class SysUser implements Serializable {
74 this.createDate = createDate; 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 public Date getLastLoginDate() { 89 public Date getLastLoginDate() {
78 return lastLoginDate; 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,6 +20,7 @@ import org.slf4j.LoggerFactory;
20 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
21 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 21 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
22 import org.springframework.stereotype.Service; 22 import org.springframework.stereotype.Service;
  23 +import org.springframework.transaction.annotation.Transactional;
23 import org.springframework.web.bind.annotation.RequestParam; 24 import org.springframework.web.bind.annotation.RequestParam;
24 25
25 import java.util.ArrayList; 26 import java.util.ArrayList;
@@ -186,7 +187,7 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem @@ -186,7 +187,7 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
186 rs.put("msg", "密码重置成功!"); 187 rs.put("msg", "密码重置成功!");
187 }else { 188 }else {
188 rs.put("status", ResponseCode.ERROR); 189 rs.put("status", ResponseCode.ERROR);
189 - rs.put("msg", "您不是超级管理员无权限重置其他用户密码"); 190 + rs.put("msg", "您不是管理员无权限重置其他用户密码");
190 } 191 }
191 }catch (Exception e){ 192 }catch (Exception e){
192 logger.error("", e); 193 logger.error("", e);
@@ -195,4 +196,10 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem @@ -195,4 +196,10 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
195 } 196 }
196 return rs; 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,6 +431,29 @@
431 }); 431 });
432 432
433 $(function () { 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 $.get('/user/currentUser', function (user) { 457 $.get('/user/currentUser', function (user) {
435 $('#indexTopUName').text(user.userName); 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 </html> 391 </html>
393 \ No newline at end of file 392 \ No newline at end of file
src/main/resources/static/pages/permission/user/changePWD.html
@@ -54,11 +54,27 @@ $(function(){ @@ -54,11 +54,27 @@ $(function(){
54 //表单 validate 54 //表单 validate
55 var error = $('.alert-danger', form); 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 $.validator.addMethod("passwordrule", function(value, element) { 74 $.validator.addMethod("passwordrule", function(value, element) {
58 var reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*?[#?!@$%^&*-.]).{8,16}$/; 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 //表单 validate 79 //表单 validate
64 form.validate({ 80 form.validate({
src/main/resources/static/pages/permission/user/forceChangePWD.html
1 <div class="row"> 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 </div> 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 </div> 48 </div>
49 49
50 <script> 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 </script> 143 </script>
128 \ No newline at end of file 144 \ No newline at end of file
src/main/resources/static/pages/permission/user/list.html
@@ -32,13 +32,13 @@ @@ -32,13 +32,13 @@
32 <thead> 32 <thead>
33 <tr role="row" class="heading"> 33 <tr role="row" class="heading">
34 <th width="3%">#</th> 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 <th width="11%">角色</th> 38 <th width="11%">角色</th>
39 <th width="10%">状态</th> 39 <th width="10%">状态</th>
40 <th width="18%">最后登录时间</th> 40 <th width="18%">最后登录时间</th>
41 - <th width="18%">操作</th> 41 + <th width="26%">操作</th>
42 </tr> 42 </tr>
43 <tr role="row" class="filter"> 43 <tr role="row" class="filter">
44 <td></td> 44 <td></td>
@@ -120,6 +120,9 @@ @@ -120,6 +120,9 @@
120 {{if obj.isAdmin}} 120 {{if obj.isAdmin}}
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> 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 {{/if}} 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 </td> 126 </td>
124 </tr> 127 </tr>
125 {{/each}} 128 {{/each}}
@@ -153,14 +156,14 @@ $(function(){ @@ -153,14 +156,14 @@ $(function(){
153 var id = $(this).data('id'); 156 var id = $(this).data('id');
154 var name = $(this).data('name'); 157 var name = $(this).data('name');
155 swal({ 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 function(){ 167 function(){
165 $.post('/user/resetPassword',{'id':id},function(result){ 168 $.post('/user/resetPassword',{'id':id},function(result){
166 if(result.status=='SUCCESS') { 169 if(result.status=='SUCCESS') {
@@ -175,7 +178,30 @@ $(function(){ @@ -175,7 +178,30 @@ $(function(){
175 jsDoQuery(getParams(), true); 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 jsDoQuery(null,true); 205 jsDoQuery(null,true);
180 206
181 //重置 207 //重置