登录/登出接口完善

This commit is contained in:
aoshiguchen
2022-08-02 22:04:32 +08:00
parent a5a2ef8a62
commit 3467cc96d3
11 changed files with 542 additions and 20 deletions
@@ -85,9 +85,10 @@ public class SqlAndParams {
if (null == paramMap) {
paramMap = new HashMap<>();
}
String originSql = sql;
List<Orderly> orderlyList = new ArrayList<>();
for(String key : paramMap.keySet()){
int index = sql.indexOf(":" + key);
int index = originSql.indexOf(":" + key);
if(-1 != index){
orderlyList.add(new Orderly(paramMap.get(key), index));
sql = sql.replaceFirst(":" + key, "?");
@@ -23,9 +23,12 @@ package fun.asgc.neutrino.core.util;
import fun.asgc.neutrino.core.cache.Cache;
import fun.asgc.neutrino.core.cache.MemoryCache;
import org.apache.commons.lang3.StringUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.*;
import java.util.function.Consumer;
/**
*
@@ -49,17 +52,288 @@ public class DateUtil {
}
/**
* 日期格式化
* 解析日期
*
* @param date 日期类
* @param pattern 日期格式
* @return 返回日期
*/
public static Date parseStr(String date, String pattern) {
if (date == null || pattern == null) {
return null;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
Date parse = null;
try {
parse = simpleDateFormat.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return parse;
}
/**
* @param date 时间。若为空,则返回空串
* @param pattern 时间格式化
* @return 格式化后的时间字符串.
*/
public static String format(Date date, String pattern) {
if (date == null) {
return "";
}
return new SimpleDateFormat(pattern).format(date);
}
/**
* @param date 日期
* @param pattern 格式
* @return 日期类型
*/
public static Date parse(String date, String pattern) {
try {
return new SimpleDateFormat(pattern).parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
/**
* 是否在指定时间段之间
*
* @param judgeTime 比较时间
* @param beginTime 开始时间
* @param endTime 结束时间
* @param flag 0-[beginTime<=judgeTime<=endTime]
* 1-[beginTime<judgeTime<=endTime]
* 2-[beginTime<=judgeTime<endTime]
* 3-[beginTime<judgeTime<endTime]
* @return 判断结果
*/
public static boolean isBetweenTimes(Date judgeTime, Date beginTime, Date endTime, int flag) {
switch (flag) {
case 0:
return (beginTime.getTime() <= judgeTime.getTime() && judgeTime.getTime() <= endTime.getTime());
case 1:
return (beginTime.getTime() < judgeTime.getTime() && judgeTime.getTime() <= endTime.getTime());
case 2:
return (beginTime.getTime() <= judgeTime.getTime() && judgeTime.getTime() < endTime.getTime());
case 3:
return (beginTime.getTime() < judgeTime.getTime() && judgeTime.getTime() < endTime.getTime());
default:
return false;
}
}
/**
* 取得日期所在月的month个月同一天<br />
*
* @param date 日期
* @param month 月
* @return 日期
*/
public static Date getMonthDay(Date date, int month) {
Calendar cal = Calendar.getInstance();
if (date != null) {
cal.setTime(date);
}
cal.add(Calendar.MONTH, month);
return cal.getTime();
}
/**
* 获取该日期当月最后一天
*
* @param date 日期
* @return 结果日期
*/
public static Date getMonthEnd(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(getDayEnd(date));
calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.add(Calendar.DAY_OF_MONTH, -1);
return calendar.getTime();
}
/**
* 计算当期时间相差的日期
*
* @param date 设置时间
* @param field 日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
* @param amount 相差的数值
* @return 计算后的日志
*/
public static Date addDate(Date date, int field, int amount) {
Calendar c = Calendar.getInstance();
if (date != null) {
c.setTime(date);
}
c.add(field, amount);
return c.getTime();
}
/**
* 计算当期时间相差的日期
*
* @param field 日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
* @param amount 相差的数值
* @return 计算后的日志
*/
public static Date addDate(int field, int amount) {
return addDate(null, field, amount);
}
/**
* 设置Calendar的小时、分钟、秒、毫秒
*
* @param calendar 日历
* @param hour 小时
* @param minute 分钟
* @param second 秒
* @param milliSecond 毫秒
* @return 结果日期
*/
public static void setCalender(Calendar calendar, int hour, int minute, int second, int milliSecond) {
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
calendar.set(Calendar.MILLISECOND, milliSecond);
}
/**
* 获取某个时间段内的每天时间日期
*
* @param beginDate 开始日期
* @param endDate 结束日期
* @return 返回结果
*/
public static List<String> getBetweenTimes(String beginDate, String endDate) {
if (StringUtils.isEmpty(beginDate) || StringUtils.isEmpty(endDate)) {
return Collections.emptyList();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dBegin = null;
Date dEnd = null;
try {
dBegin = sdf.parse(beginDate);
dEnd = sdf.parse(endDate);
} catch (ParseException e) {
e.printStackTrace();
}
if (StringUtils.isEmpty(beginDate) || StringUtils.isEmpty(endDate)) {
return Collections.emptyList();
}
return findDates(dBegin, dEnd);
}
/**
* @param dBegin 开始时间
* @param dEnd 结束时间
* @return 结果集
*/
public static List<String> findDates(Date dBegin, Date dEnd) {
List<String> lDate = new ArrayList<>();
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
lDate.add(sd.format(dBegin));
Calendar calBegin = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calBegin.setTime(dBegin);
Calendar calEnd = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calEnd.setTime(dEnd);
// 测试此日期是否在指定日期之后
while (dEnd.after(calBegin.getTime())) {
// 根据日历的规则,为给定的日历字段添加或减去指定的时间量
calBegin.add(Calendar.DAY_OF_MONTH, 1);
lDate.add(sd.format(calBegin.getTime()));
}
return lDate;
}
/**
* 取得日期所在年的下一年同一天<br />
* 注:若参数date为空,则取得第当前年所对应的下一年
*
* @param date
* @param format
* @return
*/
public static String format(Date date, String format) {
try {
return getSimpleDateFormat(format).format(date);
} catch (Exception e) {
// ignore
public static Date getNextYearDay(Date date) {
Calendar cal = Calendar.getInstance();
if (date != null) {
cal.setTime(date);
}
cal.add(Calendar.YEAR, 1);
return cal.getTime();
}
/**
* 获取指定天开始时间
*
* @param date 日期
* @return 获得该日期的开始
*/
public static Date getDayBegin(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
setCalender(calendar, 0, 0, 0, 0);
return calendar.getTime();
}
/**
* 获取当天开始时间
*
* @return 获得该日期的开始
*/
public static Date getDayBegin() {
return getDayBegin(new Date());
}
/**
* 获取指定天结束时间
*
* @param date 日期
* @return 获得该日期的结束
*/
public static Date getDayEnd(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
setCalender(calendar, 23, 59, 59, 999);
return calendar.getTime();
}
/**
* 获取指定天结束时间
*
* @param date 日期
* @return 获得该日期的结束
*/
public static Date getDayEnd2(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
setCalender(calendar, 23, 59, 59, 000);
return calendar.getTime();
}
/**
* 日期遍历接口
* @param startDate 开始日期 yyyy-MM-dd
* @param endDate 结束日期 yyyy-MM-dd
* @param consumer 执行器回调
*/
public static void dayForEach(String startDate, String endDate, Consumer<String> consumer) {
if (StringUtils.isEmpty(startDate) || StringUtils.isEmpty(endDate) || null == consumer) {
return;
}
Date current = parse(startDate, "yyyy-MM-dd");
Date end = parse(endDate, "yyyy-MM-dd");
while (!current.after(end)) {
consumer.accept(format(current, "yyyy-MM-dd"));
current = addDate(current, Calendar.DATE, 1);
}
return "";
}
}
@@ -36,7 +36,9 @@ public enum ExceptionConstant {
USER_NOT_LOGIN(1, "用户未登录"),
PARAMS_INVALID(2, "参数不正确"),
PARAMS_NOT_NULL(3, "参数[%s]不能为空"),
SYSTEM_ERROR(500, "系统异常");
USER_NAME_OR_PASSWORD_ERROR(4, "用户名或密码错误"),
SYSTEM_ERROR(500, "系统异常"),
;
private int code;
private String msg;
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.base.rest;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
/**
*
* @author: aoshiguchen
* @date: 2022/8/2
*/
public class SystemContextHolder {
private static final ThreadLocal<UserDO> userHolder = new ThreadLocal<>();
private static final ThreadLocal<String> tokenHolder = new ThreadLocal<>();
public static void remove() {
userHolder.remove();
tokenHolder.remove();
}
public static void setUser(UserDO user) {
userHolder.set(user);
}
public static UserDO getUser() {
return userHolder.get();
}
public static void setToken(String token) {
tokenHolder.set(token);
}
public static String getToken() {
return tokenHolder.get();
}
}
@@ -21,9 +21,17 @@
*/
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.core.util.StringUtil;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
import fun.asgc.neutrino.core.web.interceptor.HandlerInterceptor;
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
import fun.asgc.neutrino.proxy.server.base.rest.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.service.UserService;
import java.lang.reflect.Method;
@@ -36,8 +44,25 @@ public class BaseAuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod) throws Exception {
// TODO
Authorization authorization = targetMethod.getAnnotation(Authorization.class);
if (null == authorization || authorization.login()) {
String authorize = requestParser.getHeaderValue("Authorize");
if (StringUtil.isEmpty(authorize)) {
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
}
UserDO userDO = BeanManager.getBean(UserService.class).findByToken(authorize);
if (null == userDO) {
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
}
SystemContextHolder.setUser(userDO);
SystemContextHolder.setToken(authorize);
}
return true;
}
@Override
public void afterCompletion(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod) {
SystemContextHolder.remove();
}
}
@@ -57,9 +57,8 @@ public class IndexController {
}
@PostMapping("logout")
public LogoutRes logout(@RequestBody LogoutReq req) {
// TODO
return null;
public void logout() {
userService.logout();
}
}
@@ -0,0 +1,43 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.db.annotation.Insert;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
/**
*
* @author: aoshiguchen
* @date: 2022/8/2
*/
@Component
public interface UserLoginRecordMapper extends SqlMapper {
/**
* 新增用户登录日志
* @param userLoginRecord
* @return
*/
@Insert("insert into `user_login_record`(`user_id`,`ip`,`token`,`type`,`create_time`) values(:userId,:ip,:token,:type,:createTime)")
int add(UserLoginRecordDO userLoginRecord);
}
@@ -42,4 +42,12 @@ public interface UserMapper extends SqlMapper {
@Select("select * from user where login_name = ?")
UserDO findByLoginName(String loginName);
/**
* 根据id查询单条记录
* @param id
* @return
*/
@Select("select * from user where id = ?")
UserDO findById(Integer id);
}
@@ -22,10 +22,14 @@
package fun.asgc.neutrino.proxy.server.dal;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.db.annotation.Delete;
import fun.asgc.neutrino.core.db.annotation.Insert;
import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.UserTokenDO;
import java.util.Date;
/**
*
* @author: aoshiguchen
@@ -40,4 +44,19 @@ public interface UserTokenMapper extends SqlMapper {
*/
@Insert("insert into `user_token`(`token`,`user_id`,`expiration_time`,`create_time`,`update_time`) values (:token,:userId,:expirationTime,:createTime,:updateTime)")
int add(UserTokenDO userToken);
/**
* 根据token查询单条记录
* @param token
* @return
*/
@Select("select * from user_token where token = ? and expiration_time > ?")
UserTokenDO findByAvailableToken(String token, Long time);
/**
* 根据token删除记录
* @param token
*/
@Delete("delete from user_token where token = ?")
void deleteByToken(String token);
}
@@ -0,0 +1,64 @@
/**
* Copyright (C) 2018-2022 Zeyi information technology (Shanghai) Co., Ltd.
* <p>
* All right reserved.
* <p>
* This software is the confidential and proprietary
* information of Zeyi Company of China.
* ("Confidential Information"). You shall not disclose
* such Confidential Information and shall use it only
* in accordance with the terms of the contract agreement
* you entered into with Zeyi inc.
*/
package fun.asgc.neutrino.proxy.server.dal.entity;
import fun.asgc.neutrino.core.db.annotation.Id;
import fun.asgc.neutrino.core.db.annotation.Table;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.util.Date;
/**
*
* @author: aoshiguchen
* @date: 2022/8/2
*/
@ToString
@Data
@Accessors(chain = true)
@Table("user_login_record")
public class UserLoginRecordDO {
/**
* 类型 - 登录
*/
public static final Integer TYPE_LOGIN = 1;
/**
* 类型 - 登出
*/
public static final Integer TYPE_LOGOUT = 2;
@Id
private Integer id;
/**
* 用户ID
*/
private Integer userId;
/**
* token
*/
private String token;
/**
* ip
*/
private String ip;
/**
* 类型
*/
private Integer type;
/**
* 创建时间
*/
private Date createTime;
}
@@ -23,15 +23,21 @@ package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.web.annotation.RequestBody;
import fun.asgc.neutrino.core.util.DateUtil;
import fun.asgc.neutrino.proxy.server.base.rest.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
import fun.asgc.neutrino.proxy.server.controller.req.LoginReq;
import fun.asgc.neutrino.proxy.server.controller.res.LoginRes;
import fun.asgc.neutrino.proxy.server.dal.UserLoginRecordMapper;
import fun.asgc.neutrino.proxy.server.dal.UserMapper;
import fun.asgc.neutrino.proxy.server.dal.UserTokenMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserTokenDO;
import fun.asgc.neutrino.proxy.server.util.Md5Util;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
@@ -46,25 +52,36 @@ public class UserService {
private UserMapper userMapper;
@Autowired
private UserTokenMapper userTokenMapper;
@Autowired
private UserLoginRecordMapper userLoginRecordMapper;
public LoginRes login(LoginReq req) {
UserDO userDO = userMapper.findByLoginName(req.getLoginName());
if (null == userDO || !Md5Util.encode(req.getLoginPassword()).equals(userDO.getLoginPassword())) {
// TODO 抛出异常
throw ServiceException.create(ExceptionConstant.USER_NAME_OR_PASSWORD_ERROR);
}
String token = UUID.randomUUID().toString().replaceAll("-", "");
Date now = new Date();
// TODO 计算过期时间
Date expirationTime = DateUtil.addDate(now, Calendar.HOUR, 1);
// 缓存token
userTokenMapper.add(new UserTokenDO()
.setToken(token)
.setUserId(userDO.getId())
.setExpirationTime(now)
.setExpirationTime(expirationTime)
.setCreateTime(now)
.setUpdateTime(now)
);
// TODO 新增登录日志
// 新增用户登录日志
userLoginRecordMapper.add(new UserLoginRecordDO()
.setUserId(userDO.getId())
.setIp("111")
.setToken(token)
.setType(UserLoginRecordDO.TYPE_LOGIN)
.setCreateTime(now)
);
return new LoginRes()
.setToken(token)
@@ -72,4 +89,19 @@ public class UserService {
.setUserName(userDO.getName());
}
public void logout() {
userTokenMapper.deleteByToken(SystemContextHolder.getToken());
}
public UserDO findByToken(String token) {
Date now = new Date();
UserTokenDO userTokenDO = userTokenMapper.findByAvailableToken(token, now.getTime());
if (null == userTokenDO) {
return null;
}
UserDO userDO = userMapper.findById(userTokenDO.getUserId());
// TODO 校验用户是否已被禁用
return userDO;
}
}