👽 加强用户登录安全,超过登录次数限制登录

pull/1/head
RYAN0UP_ 2018-03-24 20:51:45 +08:00
parent 3ae12ba69f
commit f57d8254e0
9 changed files with 158 additions and 30 deletions

View File

@ -48,12 +48,25 @@ Fast,simple,powerful blog system powered by Java.
## Thanks 感谢 ## Thanks 感谢
Halo的诞生离不开下面这些开源项目: Halo的诞生离不开下面这些项目
- [IntelliJ IDEA](https://www.jetbrains.com/idea/)个人认为强大的Java IDE没有之一
- [Spring Boot](https://github.com/spring-projects/spring-boot)Spring的微服务框架 - [Spring Boot](https://github.com/spring-projects/spring-boot)Spring的微服务框架
- [Freemarker](https://freemarker.apache.org/):模板引擎,使页面静态化
- [H2 Database](https://github.com/h2database/h2database):嵌入式数据库,无需安装 - [H2 Database](https://github.com/h2database/h2database):嵌入式数据库,无需安装
- [Druid](https://github.com/alibaba/druid):阿里的数据源 - [Druid](https://github.com/alibaba/druid):阿里开发的连接池
- [Spring-data-jpa](https://github.com/spring-projects/spring-data-jpa.git)不需要写sql语句的持久层框架
- [Ehcache](http://www.ehcache.org/):缓存框架
- [Lombok](https://www.projectlombok.org/):让代码更简洁 - [Lombok](https://www.projectlombok.org/):让代码更简洁
- [Apache Commons](http://commons.apache.org/)非常好用的Java工具库
- [oh-my-email](https://github.com/biezhi/oh-my-email)可能是最小的Java邮件发送库了支持抄送、附件、模板等 - [oh-my-email](https://github.com/biezhi/oh-my-email)可能是最小的Java邮件发送库了支持抄送、附件、模板等
- [AdminLTE](https://github.com/almasaeed2010/AdminLTE)基于Bootstrap的后台模板 - [AdminLTE](https://github.com/almasaeed2010/AdminLTE)基于Bootstrap的后台模板
- [Bootstrap](https://github.com/twbs/bootstrap.git)使用最广泛的前端ui框架
- [Animate](https://github.com/daneden/animate.css.git)非常好用的css动效库
- [Editor.md](https://github.com/pandao/editor.md.git)Markdown前端编辑器遗憾作者弃坑了
- [Bootstrap-FileInput](https://github.com/kartik-v/bootstrap-fileinput.git):个人认为最好用的上传组件,没有之一
- [Font-awesome](https://github.com/FortAwesome/Font-Awesome.git):使用最广泛的字体图标库
- [Jquery](https://github.com/jquery/jquery.git)使用最广泛的JavaScript框架
- [Layer](https://github.com/sentsin/layer.git):个人认为最实用最好看的弹出层组件,没有之一
- [Jquery-Toast](https://github.com/kamranahmedse/jquery-toast-plugin):消息提示组件
- [Pjax](https://github.com/defunkt/jquery-pjax.git)pushState + ajax = pjax

View File

@ -39,11 +39,13 @@ public class MvcConfiguration implements WebMvcConfigurer {
registry.addInterceptor(loginInterceptor) registry.addInterceptor(loginInterceptor)
.addPathPatterns("/admin/**") .addPathPatterns("/admin/**")
.excludePathPatterns("/admin/login") .excludePathPatterns("/admin/login")
.excludePathPatterns("/admin/getLogin"); .excludePathPatterns("/admin/getLogin")
//registry.addInterceptor(installInterceptor) .excludePathPatterns("/static/**");
// .addPathPatterns("/**") registry.addInterceptor(installInterceptor)
// .excludePathPatterns("/install") .addPathPatterns("/**")
// .excludePathPatterns("/install/do"); .excludePathPatterns("/install")
.excludePathPatterns("/install/do")
.excludePathPatterns("/static/**");
} }
/** /**

View File

@ -4,6 +4,7 @@ import lombok.Data;
import javax.persistence.*; import javax.persistence.*;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date;
/** /**
* @author : RYAN0UP * @author : RYAN0UP
@ -24,28 +25,49 @@ public class User implements Serializable{
@Id @Id
@GeneratedValue @GeneratedValue
private Long userId; private Long userId;
/** /**
* *
*/ */
private String userName; private String userName;
/** /**
* *
*/ */
private String userDisplayName; private String userDisplayName;
/** /**
* *
*/ */
private String userPass; private String userPass;
/** /**
* *
*/ */
private String userEmail; private String userEmail;
/** /**
* *
*/ */
private String userAvatar; private String userAvatar;
/** /**
* *
*/ */
private String userDesc; private String userDesc;
/**
*
*/
private String loginEnable;
/**
*
*/
private Date loginLast;
/**
*
*/
private Integer loginError;
} }

View File

@ -2,6 +2,7 @@ package cc.ryanc.halo.service;
import cc.ryanc.halo.model.domain.User; import cc.ryanc.halo.model.domain.User;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
@ -50,4 +51,30 @@ public interface UserService {
* @return user * @return user
*/ */
User findByUserIdAndUserPass(Long userId,String userPass); User findByUserIdAndUserPass(Long userId,String userPass);
/**
*
*
* @param enable enable
*/
void updateUserLoginEnable(String enable);
/**
*
*
* @param lastDate lastDate
*/
User updateUserLoginLast(Date lastDate);
/**
*
*
* @param error error
*/
Integer updateUserLoginError();
/**
*
*/
User updateUserNormal();
} }

View File

@ -6,6 +6,7 @@ import cc.ryanc.halo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
@ -75,4 +76,55 @@ public class UserServiceImpl implements UserService {
public User findByUserIdAndUserPass(Long userId, String userPass) { public User findByUserIdAndUserPass(Long userId, String userPass) {
return userRepository.findByUserIdAndUserPass(userId,userPass); return userRepository.findByUserIdAndUserPass(userId,userPass);
} }
/**
*
*
* @param enable enable
*/
@Override
public void updateUserLoginEnable(String enable) {
User user = this.findAllUser().get(0);
user.setLoginEnable(enable);
userRepository.save(user);
}
/**
*
*
* @param lastDate lastDate
*/
@Override
public User updateUserLoginLast(Date lastDate) {
User user = this.findAllUser().get(0);
user.setLoginLast(lastDate);
userRepository.save(user);
return user;
}
/**
*
*
* @param error error
*/
@Override
public Integer updateUserLoginError() {
User user = this.findAllUser().get(0);
user.setLoginError(user.getLoginError()+1);
userRepository.save(user);
return user.getLoginError();
}
/**
*
*/
@Override
public User updateUserNormal() {
User user = this.findAllUser().get(0);
user.setLoginEnable("true");
user.setLoginError(0);
user.setLoginLast(new Date());
userRepository.save(user);
return user;
}
} }

View File

@ -115,30 +115,43 @@ public class AdminController extends BaseController{
*/ */
@PostMapping(value = "/getLogin") @PostMapping(value = "/getLogin")
@ResponseBody @ResponseBody
public boolean getLogin(@ModelAttribute("loginName") String loginName, public String getLogin(@ModelAttribute("loginName") String loginName,
@ModelAttribute("loginPwd") String loginPwd, @ModelAttribute("loginPwd") String loginPwd,
HttpSession session){ HttpSession session){
String status = "false";
try { try {
List<User> users = null; User aUser = userService.findAllUser().get(0);
Pattern patternEmail = Pattern.compile("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}"); User user = null;
Matcher matcher = patternEmail.matcher(loginName); if("false".equals(aUser.getLoginEnable())){
if(matcher.find()){ status = "disable";
users = userService.userLoginByEmail(loginName,HaloUtil.getMD5(loginPwd));
}else{ }else{
users = userService.userLoginByName(loginName,HaloUtil.getMD5(loginPwd)); //验证是否是邮箱登录
} Pattern patternEmail = Pattern.compile("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}");
if(null!=users){ Matcher matcher = patternEmail.matcher(loginName);
session.setAttribute(HaloConst.USER_SESSION_KEY, users.get(0)); if(matcher.find()){
log.info("用户["+ users.get(0).getUserName()+"]登录成功!"); user = userService.userLoginByEmail(loginName,HaloUtil.getMD5(loginPwd)).get(0);
logsService.saveByLogs(new Logs(LogsRecord.LOGIN,LogsRecord.LOGIN_SUCCESS,HaloUtil.getIpAddr(request), HaloUtil.getDate())); }else{
return true; user = userService.userLoginByName(loginName,HaloUtil.getMD5(loginPwd)).get(0);
}else{ }
logsService.saveByLogs(new Logs(LogsRecord.LOGIN,LogsRecord.LOGIN_ERROR,HaloUtil.getIpAddr(request),new Date())); if(aUser==user){
session.setAttribute(HaloConst.USER_SESSION_KEY, user);
//重置用户的登录状态为正常
userService.updateUserNormal();
userService.updateUserLoginLast(new Date());
logsService.saveByLogs(new Logs(LogsRecord.LOGIN,LogsRecord.LOGIN_SUCCESS,HaloUtil.getIpAddr(request), HaloUtil.getDate()));
status = "true";
}
} }
}catch (Exception e){ }catch (Exception e){
Integer errorCount = userService.updateUserLoginError();
if(errorCount>=5){
userService.updateUserLoginEnable("false");
}
userService.updateUserLoginLast(new Date());
logsService.saveByLogs(new Logs(LogsRecord.LOGIN,LogsRecord.LOGIN_ERROR,HaloUtil.getIpAddr(request),new Date()));
log.error("登录失败!:"+e.getMessage()); log.error("登录失败!:"+e.getMessage());
} }
return false; return status;
} }
/** /**

View File

@ -22,7 +22,6 @@ public class InstallInterceptor implements HandlerInterceptor {
File basePath = new File(ResourceUtils.getURL("classpath:").getPath()); File basePath = new File(ResourceUtils.getURL("classpath:").getPath());
File installFile = new File(basePath.getAbsolutePath(), "install.lock"); File installFile = new File(basePath.getAbsolutePath(), "install.lock");
if(installFile.exists()){ if(installFile.exists()){
response.sendRedirect("/");
return true; return true;
} }
response.sendRedirect("/install"); response.sendRedirect("/install");

View File

@ -27,7 +27,7 @@ spring:
jpa: jpa:
hibernate: hibernate:
ddl-auto: update ddl-auto: update
show-sql: false show-sql: true
database-platform: org.hibernate.dialect.H2Dialect database-platform: org.hibernate.dialect.H2Dialect
# freemarker配置 # freemarker配置

View File

@ -62,8 +62,8 @@
'loginName': name, 'loginName': name,
'loginPwd': pwd 'loginPwd': pwd
}, },
success: function (data) { success: function (status) {
if(data==true){ if(status=="true"){
$.toast({ $.toast({
text: "登录成功!", text: "登录成功!",
heading: '提示', heading: '提示',
@ -80,10 +80,10 @@
window.location.href="/admin"; window.location.href="/admin";
} }
}); });
}else if(data=="wait"){ }else if(status=="disable"){
$('.login-body').addClass('animate shake'); $('.login-body').addClass('animate shake');
$.toast({ $.toast({
text: "密码错误已达到5次30分钟后再试", text: "密码错误已达到5次10分钟后再试",
heading: '提示', heading: '提示',
icon: 'error', icon: 'error',
showHideTransition: 'fade', showHideTransition: 'fade',