Commit 21bded0c69945973062d921af5d82857181e9ea2

Authored by 徐烜
Committed by 王通
1 parent e3e011f6

1.加入密码过期机制

src/main/java/com/bsth/controller/sys/UserController.java
... ... @@ -5,7 +5,6 @@ import com.bsth.common.ResponseCode;
5 5 import com.bsth.controller.BaseController;
6 6 import com.bsth.controller.sys.dto.CompanyData;
7 7 import com.bsth.controller.sys.util.RSAUtils;
8   -import com.bsth.email.entity.EmailBean;
9 8 import com.bsth.entity.sys.CompanyAuthority;
10 9 import com.bsth.entity.sys.Role;
11 10 import com.bsth.entity.sys.SysUser;
... ... @@ -13,12 +12,13 @@ import com.bsth.security.SsoConfig;
13 12 import com.bsth.security.util.SecurityUtils;
14 13 import com.bsth.service.sys.CompanyAuthorityService;
15 14 import com.bsth.service.sys.SysUserService;
16   -import com.bsth.service.sys.impl.PwdGenerator;
17 15 import com.bsth.util.HttpClientUtils;
18   -import com.bsth.util.IpUtils;
19 16 import com.fasterxml.jackson.databind.ObjectMapper;
20 17 import com.google.common.collect.ArrayListMultimap;
21 18 import org.apache.commons.lang3.StringUtils;
  19 +import org.joda.time.DateTime;
  20 +import org.joda.time.Period;
  21 +import org.joda.time.PeriodType;
22 22 import org.slf4j.Logger;
23 23 import org.slf4j.LoggerFactory;
24 24 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -198,6 +198,25 @@ public class UserController extends BaseController<SysUser, Integer> {
198 198 return rs;
199 199 }
200 200  
  201 + // 检验密码有效期
  202 + Date lastPwdDate = user.getLastPwdDate();
  203 + if (lastPwdDate != null) {
  204 + if (user.getPwdExpiredDate().before(new Date())) {
  205 + return put(rs, "msg", "密码已过期,不能登录,请联系管理员");
  206 + }
  207 +
  208 + Integer validPeriod = user.getPwdValidPeriod();
  209 + if (validPeriod == null) {
  210 + validPeriod = 30;
  211 + }
  212 + Period p = new Period(new DateTime(lastPwdDate), new DateTime(new Date()), PeriodType.days());
  213 + if (p.getDays() > validPeriod) {
  214 + return put(rs, "msg", "天没有修改密码,不能登录,请联系管理员");
  215 + }
  216 + } else {
  217 + return put(rs, "msg", "从未更新过密码,不能登录,请联系管理员");
  218 + }
  219 +
201 220 // 弱密码检查
202 221 Matcher matcher = pattern.matcher(password);
203 222 if (!matcher.matches()) {
... ... @@ -385,6 +404,18 @@ public class UserController extends BaseController<SysUser, Integer> {
385 404 return msg;
386 405 }
387 406  
  407 + @RequestMapping(value = "/validPWDExpired", method = RequestMethod.GET)
  408 + public String validPWDExpired() {
  409 + try {
  410 + SysUser sysUser = SecurityUtils.getCurrentUser();
  411 + this.sysUserService.validPWDExpired(sysUser.getUserName());
  412 + return "ok";
  413 + } catch (Exception exp) {
  414 + exp.printStackTrace();
  415 + return exp.getMessage();
  416 + }
  417 + }
  418 +
388 419 @RequestMapping(value = "/register", method = RequestMethod.POST)
389 420 public Map<String, Object> register(SysUser u) {
390 421 return sysUserService.register(u);
... ... @@ -398,8 +429,8 @@ public class UserController extends BaseController&lt;SysUser, Integer&gt; {
398 429  
399 430 // 重置密码
400 431 @RequestMapping(value = "/resetPassword", method = RequestMethod.POST)
401   - public Map<String, Object> resetPassword(@RequestParam Integer id) {
402   - return sysUserService.resetPassword(id);
  432 + public Map<String, Object> resetPassword(@RequestParam Integer id, @RequestParam Integer pwdValidPeriod) {
  433 + return sysUserService.resetPassword(id, pwdValidPeriod);
403 434 }
404 435  
405 436 /**
... ...
src/main/java/com/bsth/entity/sys/SysUser.java
... ... @@ -2,6 +2,7 @@ package com.bsth.entity.sys;
2 2  
3 3 import com.fasterxml.jackson.annotation.JsonIgnore;
4 4 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
  5 +import org.joda.time.DateTime;
5 6  
6 7 import javax.persistence.*;
7 8 import java.io.Serializable;
... ... @@ -38,13 +39,23 @@ public class SysUser implements Serializable {
38 39  
39 40 private Date lastLoginDate;
40 41  
  42 + /** 最近密码更新时间 */
  43 + private Date lastPwdDate;
  44 + /** 密码有效期 */
  45 + private Integer pwdValidPeriod;
  46 +
41 47 private String agencies;
42 48  
43 49 private boolean enabled;
44 50  
45 51 @ManyToMany(fetch = FetchType.EAGER)
46 52 private Set<Role> roles = new LinkedHashSet<>();
47   -
  53 +
  54 + /**
  55 + * 密码过期时间
  56 + */
  57 + @Transient
  58 + private Date pwdExpiredDate;
48 59  
49 60 public Integer getId() {
50 61 return id;
... ... @@ -125,4 +136,33 @@ public class SysUser implements Serializable {
125 136 public void setRoles(Set<Role> roles) {
126 137 this.roles = roles;
127 138 }
  139 +
  140 + public Date getLastPwdDate() {
  141 + return lastPwdDate;
  142 + }
  143 +
  144 + public void setLastPwdDate(Date lastPwdDate) {
  145 + this.lastPwdDate = lastPwdDate;
  146 + }
  147 +
  148 + public Integer getPwdValidPeriod() {
  149 + return pwdValidPeriod;
  150 + }
  151 +
  152 + public void setPwdValidPeriod(Integer pwdValidPeriod) {
  153 + this.pwdValidPeriod = pwdValidPeriod;
  154 + }
  155 +
  156 + public Date getPwdExpiredDate() {
  157 + DateTime dateTime = new DateTime(getLastPwdDate());
  158 + if (pwdValidPeriod != null) {
  159 + dateTime = dateTime.plusDays(pwdValidPeriod);
  160 + }
  161 +
  162 + return dateTime.toDate();
  163 + }
  164 +
  165 + public void setPwdExpiredDate(Date pwdExpiredDate) {
  166 + this.pwdExpiredDate = pwdExpiredDate;
  167 + }
128 168 }
... ...
src/main/java/com/bsth/repository/sys/SysUserRepository.java
... ... @@ -22,7 +22,7 @@ public interface SysUserRepository extends BaseRepository&lt;SysUser, Integer&gt;{
22 22  
23 23 @Transactional
24 24 @Modifying
25   - @Query(value="update bsth_c_sys_user set password=?2 where id=?1",nativeQuery=true)
  25 + @Query(value="update bsth_c_sys_user set password=?2, last_pwd_date = now() where id=?1",nativeQuery=true)
26 26 int changePWD(int id,String newPWD);
27 27  
28 28 @EntityGraph(value = "sysUser_role", type = EntityGraph.EntityGraphType.FETCH)
... ...
src/main/java/com/bsth/service/sys/SysUserService.java
... ... @@ -2,7 +2,6 @@ package com.bsth.service.sys;
2 2  
3 3 import com.bsth.entity.sys.SysUser;
4 4 import com.bsth.service.BaseService;
5   -import org.springframework.web.bind.annotation.RequestParam;
6 5  
7 6 import java.util.List;
8 7 import java.util.Map;
... ... @@ -15,11 +14,17 @@ public interface SysUserService extends BaseService&lt;SysUser, Integer&gt;{
15 14  
16 15 int changePWD(int id,String newPWD);
17 16  
  17 + /**
  18 + * 检测指定用户密码是否过期
  19 + * @param userName 用户名
  20 + */
  21 + boolean validPWDExpired(String userName);
  22 +
18 23 Map<String,Object> register(SysUser u);
19 24  
20 25 List<SysUser> findAll_distinct();
21 26  
22   - Map<String, Object> resetPassword(@RequestParam Integer id);
  27 + Map<String, Object> resetPassword(Integer id, Integer pwdValidPeriod);
23 28  
24 29 void recordLoginDate(String userName);
25 30 }
... ...
src/main/java/com/bsth/service/sys/impl/SysUserServiceImpl.java
... ... @@ -2,7 +2,6 @@ package com.bsth.service.sys.impl;
2 2  
3 3 import com.bsth.common.ResponseCode;
4 4 import com.bsth.controller.sys.util.RSAUtils;
5   -import com.bsth.email.SendEmailController;
6 5 import com.bsth.email.entity.EmailBean;
7 6 import com.bsth.entity.sys.Role;
8 7 import com.bsth.entity.sys.SysUser;
... ... @@ -15,13 +14,14 @@ import com.bsth.util.IpUtils;
15 14 import com.bsth.util.MailUtils;
16 15 import com.google.gson.Gson;
17 16 import com.google.gson.reflect.TypeToken;
  17 +import org.joda.time.DateTime;
  18 +import org.joda.time.Days;
18 19 import org.slf4j.Logger;
19 20 import org.slf4j.LoggerFactory;
20 21 import org.springframework.beans.factory.annotation.Autowired;
21 22 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
22 23 import org.springframework.stereotype.Service;
23 24 import org.springframework.transaction.annotation.Transactional;
24   -import org.springframework.web.bind.annotation.RequestParam;
25 25  
26 26 import java.util.ArrayList;
27 27 import java.util.HashMap;
... ... @@ -72,7 +72,33 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
72 72 return sysUserRepository.changePWD(id,new BCryptPasswordEncoder(4).encode(newPWD));
73 73 }
74 74  
75   - @Override
  75 + @Override
  76 + public boolean validPWDExpired(String userName) {
  77 + SysUser sysUser = this.sysUserRepository.findByUserName(userName);
  78 + if (sysUser == null) {
  79 + throw new RuntimeException("用户[" + userName + "]不存在!");
  80 + }
  81 + if (sysUser.getPwdValidPeriod() == null || sysUser.getLastPwdDate() == null) {
  82 + // 如果没有设定密码过期时间,判定为不过期
  83 + return true;
  84 + }
  85 + DateTime now = new DateTime();
  86 + DateTime lastPwdDate = new DateTime(sysUser.getLastPwdDate());
  87 + Integer now_period_days = Days.daysBetween(lastPwdDate, now).getDays();
  88 + Integer expiredTipDays = 3; // 密码过期提前提示天数
  89 + if (now_period_days < (sysUser.getPwdValidPeriod() - expiredTipDays)) {
  90 + return true;
  91 + } else if (now_period_days >= (sysUser.getPwdValidPeriod() - expiredTipDays) &&
  92 + now_period_days < sysUser.getPwdValidPeriod()) {
  93 + // 快过期前提示
  94 + throw new RuntimeException("当前用户密码还有[" + (sysUser.getPwdValidPeriod() - now_period_days) + "]天过期!");
  95 + } else {
  96 + throw new RuntimeException("当前用户密码已过期!");
  97 + }
  98 +
  99 + }
  100 +
  101 + @Override
76 102 public Map<String, Object> register(SysUser u) {
77 103 Map<String, Object> rs = new HashMap();
78 104 boolean isLegality = false;
... ... @@ -161,7 +187,8 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
161 187 }
162 188  
163 189 @Override
164   - public Map<String, Object> resetPassword(@RequestParam Integer id){
  190 + @Transactional
  191 + public Map<String, Object> resetPassword(Integer id, Integer pwdValidPeriod){
165 192 Map<String, Object> rs = new HashMap();
166 193 try{
167 194 // 获取当前用户
... ... @@ -176,7 +203,10 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
176 203 }
177 204 if(Legality){
178 205 String pwd = PwdGenerator.randomPassword(16);
179   - sysUserRepository.changePWD(id,new BCryptPasswordEncoder(4).encode(pwd));
  206 + user = sysUserRepository.findById(id).get();
  207 + user.setPwdValidPeriod(pwdValidPeriod);
  208 + sysUserRepository.save(user);
  209 + sysUserRepository.changePWD(id, new BCryptPasswordEncoder(4).encode(pwd));
180 210 //发送邮件
181 211 EmailBean mail = new EmailBean();
182 212 mail.setSubject(IpUtils.getLocalIpAddress() +":密码重置");
... ...
src/main/resources/static/pages/home.html
... ... @@ -73,7 +73,7 @@
73 73 </div>
74 74  
75 75 <script type="text/javascript">
76   - $.ajax({
  76 + /*$.ajax({
77 77 url: '/eci/validate_get_destroy_info',
78 78 dataType: "json",
79 79 success: function(rs) {
... ... @@ -111,6 +111,25 @@
111 111 }
112 112 }
113 113 }
  114 + });*/
  115 +
  116 + $.get("/user/validPWDExpired", function(msg) {
  117 + if ("ok" === msg) {
  118 + return;
  119 + }
  120 +
  121 + var htmlText = [];
  122 + htmlText.push("<span style='font-weight: bold; font-style: italic; '>" + msg + "</span></br>");
  123 + swal({
  124 + title: "账户密码提示",
  125 + text: htmlText.join("</br>"),
  126 + html: true,
  127 + type: "warning",
  128 + showCancelButton: true,
  129 + cancelButtonText: "关闭",
  130 + confirmButtonColor: "#3598dc",
  131 + closeOnConfirm: false
  132 + });
114 133 });
115 134  
116 135 </script>
... ...
src/main/resources/static/pages/permission/user/list.html
... ... @@ -118,7 +118,7 @@
118 118 <!--<button type="button" class="btn btn-sm line_allot_btn" data-id="{{obj.id}}">线调线路分配</button>-->
119 119 {{/if}}
120 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-last="{{obj.lastPwdDate}}"><i class="fa fa-undo"></i> 重置密码</a>
122 122 {{/if}}
123 123 {{if obj.isAdmin}}
124 124 <a class="btn btn-sm red btn-outline unlock" data-name="{{obj.userName}}" data-pjax><i class="fa fa-unlock"></i> 解除锁定</a>
... ... @@ -153,31 +153,24 @@ $(function(){
153 153  
154 154 setTimeout(function () {
155 155 $(document).on('click', 'a.reset_password', function () {
156   - var id = $(this).data('id');
157   - var name = $(this).data('name');
158   - swal({
159   - title: "重置密码",
160   - text: "将登录名为"+name+"的用户,密码重置为随机密码!",
161   - type: "warning",
162   - showCancelButton: true,
163   - confirmButtonColor: "#DD6B55",
164   - confirmButtonText: "重置",
165   - cancelButtonText: "取消",
166   - closeOnConfirm: false },
167   - function(){
168   - $.post('/user/resetPassword',{'id':id},function(result){
169   - if(result.status=='SUCCESS') {
170   - // 弹出添加成功提示消息
171   - swal("登录名为"+name+"的用户密码重置成功!", "success");
172   - } else if(result.status=='ERROR') {
173   - // 弹出添加失败提示消息
174   - swal("重置失败!", result.msg+",请联系开发人员!", "ERROR");
175   - }
176   - // loadPage('list.html');
177   - // 发布后刷新页面
178   - jsDoQuery(getParams(), true);
179   - });
180   - });
  156 + var id = $(this).data('id'), name = $(this).data('name'), last = $(this).data('last');
  157 + $.get('/pages/permission/user/resetPWD.html', function (content) {
  158 + layer.open({
  159 + type: 1,
  160 + area: ['600px', '360px'],
  161 + content: content,
  162 + title: '修改密码',
  163 + shift: 5,
  164 + scrollbar: false,
  165 + success: function (layero, index) {
  166 + $(layero).find('#user_id').val(id);
  167 + $(layero).find('#user_name').val(name);
  168 + debugger
  169 + $(layero).find('#last_pwd_date').val(last ? moment(last).format("YYYY-MM-DD HH:mm:ss") : '');
  170 + $(layero).find('#window_index').val(index);
  171 + }
  172 + });
  173 + });
181 174 }).on('click', 'a.unlock', function () {
182 175 var name = $(this).data('name');
183 176 swal({
... ... @@ -360,4 +353,23 @@ function changeEnabled(id,enabled){
360 353 jsDoQuery(null, true);
361 354 })
362 355 }
  356 +// 重置密码
  357 +function resetPassword(userId, ld) {
  358 + $.get('/pages/permission/user/resetPWD.html', function (content) {
  359 + layer.open({
  360 + type: 1,
  361 + area: ['600px', '360px'],
  362 + content: content,
  363 + title: '修改密码',
  364 + shift: 5,
  365 + scrollbar: false,
  366 + success: function (layero, index) {
  367 + $(layero).find('#user_id').val(userId);
  368 + $(layero).find('#last_pwd_date').val(ld ? moment(ld).format("YYYY-MM-DD HH:mm:ss") : '');
  369 + $(layero).find('#window_index').val(index);
  370 + }
  371 + });
  372 + });
  373 +
  374 +}
363 375 </script>
364 376 \ No newline at end of file
... ...
src/main/resources/static/pages/permission/user/resetPWD.html 0 → 100644
  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 + <input type="hidden" id="window_index" name="window_index">
  6 + <div class="portlet-body">
  7 + <form class="form-horizontal" id="resetPWDForm">
  8 + <input type="hidden" id="user_id" name="id">
  9 + <input type="hidden" id="user_name">
  10 + <div class="form-group" style="margin-top: 60px">
  11 + <label class="control-label col-md-4">最近密码更新时间:
  12 + </label>
  13 + <div class="col-md-6">
  14 + <div class="input-icon right">
  15 + <i class="fa"></i>
  16 + <input type="text" readonly class="form-control" id="last_pwd_date" /> </div>
  17 + </div>
  18 + </div>
  19 +
  20 + <div class="form-group" >
  21 + <label class="control-label col-md-4">密码有效期(天):
  22 + </label>
  23 + <div class="col-md-6">
  24 + <div class="input-icon right">
  25 + <i class="fa"></i>
  26 + <input type="number" class="form-control" name="pwdValidPeriod" id="pwd_valid_period" value="30" /> </div>
  27 + </div>
  28 + </div>
  29 + <div class="form-actions">
  30 + <div class="row">
  31 + <div class="col-md-offset-5 col-md-7">
  32 + <button type="button" id="confirm" class="btn green">确定</button>
  33 + <button type="button" class="btn default">取消</button>
  34 + </div>
  35 + </div>
  36 + </div>
  37 + </form>
  38 + </div>
  39 + </div>
  40 + </div>
  41 +</div>
  42 +
  43 +
  44 +<script>
  45 + $(function(){
  46 + $("#confirm").on('click',function(){
  47 + var data = $('#resetPWDForm').serializeJSON();
  48 + var index = $('#window_index').val(), name = $('#user_name').val();
  49 + $.post('/user/resetPassword', data, function(result) {
  50 + parent.layer.close(index);
  51 + if(result.status == 'SUCCESS') {
  52 + // 弹出添加成功提示消息
  53 + swal('登录名为' + name + '的用户密码重置成功!', 'success');
  54 + } else if(result.status == 'ERROR') {
  55 + // 弹出添加失败提示消息
  56 + swal('重置失败!', result.msg + ',请联系开发人员!', 'ERROR');
  57 + }
  58 + });
  59 + });
  60 +
  61 + $("#pwd_cancel").on('click', function() {
  62 + var index = $('#window_index').val();
  63 + parent.layer.close(index);
  64 + });
  65 + });
  66 +</script>
0 67 \ No newline at end of file
... ...