feat:github登陆接入
This commit is contained in:
parent
cc71076b45
commit
1196926ac9
@ -1,9 +1,12 @@
|
|||||||
package com.fanxb.bookmark.business.user.controller;
|
package com.fanxb.bookmark.business.user.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.fanxb.bookmark.business.user.vo.LoginBody;
|
import com.fanxb.bookmark.business.user.service.OAuthService;
|
||||||
import com.fanxb.bookmark.business.user.vo.RegisterBody;
|
|
||||||
import com.fanxb.bookmark.business.user.service.UserService;
|
import com.fanxb.bookmark.business.user.service.UserService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.LoginBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.OAuthBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.RegisterBody;
|
||||||
|
import com.fanxb.bookmark.business.user.service.impl.UserServiceImpl;
|
||||||
import com.fanxb.bookmark.common.entity.Result;
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
import com.fanxb.bookmark.common.util.UserContextHolder;
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
@ -22,8 +25,16 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
@RequestMapping("/user")
|
@RequestMapping("/user")
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
|
private final UserServiceImpl userServiceImpl;
|
||||||
|
private final OAuthService oAuthService;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserService userService;
|
public UserController(UserServiceImpl userServiceImpl, OAuthService oAuthService, UserService userService) {
|
||||||
|
this.userServiceImpl = userServiceImpl;
|
||||||
|
this.oAuthService = oAuthService;
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 获取验证码
|
* Description: 获取验证码
|
||||||
@ -35,7 +46,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/authCode")
|
@GetMapping("/authCode")
|
||||||
public Result getAuthCode(@Param("email") String email) {
|
public Result getAuthCode(@Param("email") String email) {
|
||||||
userService.sendAuthCode(email);
|
userServiceImpl.sendAuthCode(email);
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +60,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PutMapping("")
|
@PutMapping("")
|
||||||
public Result register(@RequestBody RegisterBody body) {
|
public Result register(@RequestBody RegisterBody body) {
|
||||||
return Result.success(userService.register(body));
|
return Result.success(userServiceImpl.register(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +72,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/currentUserInfo")
|
@GetMapping("/currentUserInfo")
|
||||||
public Result currentUserInfo() {
|
public Result currentUserInfo() {
|
||||||
return Result.success(userService.getUserInfo(UserContextHolder.get().getUserId()));
|
return Result.success(userServiceImpl.getUserInfo(UserContextHolder.get().getUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -72,7 +83,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/icon")
|
@PostMapping("/icon")
|
||||||
public Result pushIcon(@RequestParam("file") MultipartFile file) throws Exception {
|
public Result pushIcon(@RequestParam("file") MultipartFile file) throws Exception {
|
||||||
return Result.success(userService.updateIcon(file));
|
return Result.success(userServiceImpl.updateIcon(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,7 +96,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public Result login(@RequestBody LoginBody body) {
|
public Result login(@RequestBody LoginBody body) {
|
||||||
return Result.success(userService.login(body));
|
return Result.success(userServiceImpl.login(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,7 +109,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/resetPassword")
|
@PostMapping("/resetPassword")
|
||||||
public Result resetPassword(@RequestBody RegisterBody body) {
|
public Result resetPassword(@RequestBody RegisterBody body) {
|
||||||
userService.resetPassword(body);
|
userServiceImpl.resetPassword(body);
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +123,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/checkPassword")
|
@PostMapping("/checkPassword")
|
||||||
public Result checkPassword(@RequestBody JSONObject obj) {
|
public Result checkPassword(@RequestBody JSONObject obj) {
|
||||||
return Result.success(userService.checkPassword(obj.getString("password")));
|
return Result.success(userServiceImpl.checkPassword(obj.getString("password")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/loginStatus")
|
@GetMapping("/loginStatus")
|
||||||
@ -120,5 +131,28 @@ public class UserController {
|
|||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登陆
|
||||||
|
*
|
||||||
|
* @param body 入参
|
||||||
|
* @return com.fanxb.bookmark.common.entity.Result
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/10
|
||||||
|
*/
|
||||||
|
@PostMapping("oAuthLogin")
|
||||||
|
public Result oAuthLogin(@RequestBody OAuthBody body) {
|
||||||
|
return Result.success(oAuthService.oAuthCheck(body));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户version
|
||||||
|
*
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@GetMapping("/version")
|
||||||
|
public Result getUserVersion() {
|
||||||
|
return Result.success(userService.getCurrentUserVersion(UserContextHolder.get().getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.fanxb.bookmark.business.user.dao;
|
|||||||
import com.fanxb.bookmark.common.entity.User;
|
import com.fanxb.bookmark.common.entity.User;
|
||||||
import com.fanxb.bookmark.common.entity.redis.UserBookmarkUpdate;
|
import com.fanxb.bookmark.common.entity.redis.UserBookmarkUpdate;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
import org.apache.ibatis.annotations.Update;
|
import org.apache.ibatis.annotations.Update;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ public interface UserDao {
|
|||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/30 16:08
|
* @date 2019/7/30 16:08
|
||||||
*/
|
*/
|
||||||
User selectByUserId(int userId);
|
User selectByUserIdOrGithubId(@Param("userId") Integer userId, @Param("githubId") Long githubId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 更新用户icon
|
* Description: 更新用户icon
|
||||||
@ -103,10 +104,10 @@ public interface UserDao {
|
|||||||
* 更新用户新邮箱
|
* 更新用户新邮箱
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @param newPassword userId
|
* @param newEmail email
|
||||||
*/
|
*/
|
||||||
@Update("update user set newEmail=#{newPassword} where userId= #{userId}")
|
@Update("update user set newEmail=#{newEmail} where userId= #{userId}")
|
||||||
void updateNewEmailByUserId(@Param("userId") int userId, @Param("newPassword") String newPassword);
|
void updateNewEmailByUserId(@Param("userId") int userId, @Param("newEmail") String newEmail);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新邮箱校验成功,更新邮箱
|
* 新邮箱校验成功,更新邮箱
|
||||||
@ -135,4 +136,36 @@ public interface UserDao {
|
|||||||
*/
|
*/
|
||||||
@Update("update user set version=version+1")
|
@Update("update user set version=version+1")
|
||||||
void updateAllBookmarkUpdateVersion();
|
void updateAllBookmarkUpdateVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断用户名是否存在
|
||||||
|
*
|
||||||
|
* @param name name
|
||||||
|
* @return boolean
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@Select("select count(1) from user where username=#{name}")
|
||||||
|
boolean usernameExist(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新githubId
|
||||||
|
*
|
||||||
|
* @param user user
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@Update("update user set githubId=#{githubId},email=#{email} where userId=#{userId}")
|
||||||
|
void updateEmailAndGithubId(User user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户版本
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @return int
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@Select("select version from user where userId=#{userId}")
|
||||||
|
int getUserVersion(int userId);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ public class BaseInfoService {
|
|||||||
|
|
||||||
public void changePassword(UpdatePasswordBody body) {
|
public void changePassword(UpdatePasswordBody body) {
|
||||||
int userId = UserContextHolder.get().getUserId();
|
int userId = UserContextHolder.get().getUserId();
|
||||||
String password = userDao.selectByUserId(userId).getPassword();
|
String password = userDao.selectByUserIdOrGithubId(userId, null).getPassword();
|
||||||
if (!StrUtil.equals(password, HashUtil.getPassword(body.getOldPassword()))) {
|
if (!StrUtil.equals(password, HashUtil.getPassword(body.getOldPassword()))) {
|
||||||
throw new CustomException("旧密码错误");
|
throw new CustomException("旧密码错误");
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ public class BaseInfoService {
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateEmail(EmailUpdateBody body) {
|
public void updateEmail(EmailUpdateBody body) {
|
||||||
int userId = UserContextHolder.get().getUserId();
|
int userId = UserContextHolder.get().getUserId();
|
||||||
String oldPassword = userDao.selectByUserId(userId).getPassword();
|
String oldPassword = userDao.selectByUserIdOrGithubId(userId, null).getPassword();
|
||||||
if (!StrUtil.equals(oldPassword, HashUtil.getPassword(body.getOldPassword()))) {
|
if (!StrUtil.equals(oldPassword, HashUtil.getPassword(body.getOldPassword()))) {
|
||||||
throw new CustomException("密码校验失败,无法更新email");
|
throw new CustomException("密码校验失败,无法更新email");
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.fanxb.bookmark.business.user.service;
|
package com.fanxb.bookmark.business.user.service;
|
||||||
|
|
||||||
public class OAuthService {
|
import com.fanxb.bookmark.business.user.vo.OAuthBody;
|
||||||
|
|
||||||
|
public interface OAuthService {
|
||||||
|
|
||||||
|
String oAuthCheck(OAuthBody body);
|
||||||
}
|
}
|
||||||
|
@ -1,219 +1,43 @@
|
|||||||
package com.fanxb.bookmark.business.user.service;
|
package com.fanxb.bookmark.business.user.service;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.constant.FileConstant;
|
import com.fanxb.bookmark.common.util.TimeUtil;
|
||||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
|
||||||
import com.fanxb.bookmark.business.user.vo.LoginBody;
|
|
||||||
import com.fanxb.bookmark.business.user.vo.LoginRes;
|
|
||||||
import com.fanxb.bookmark.business.user.vo.RegisterBody;
|
|
||||||
import com.fanxb.bookmark.common.constant.Constant;
|
|
||||||
import com.fanxb.bookmark.common.constant.NumberConstant;
|
|
||||||
import com.fanxb.bookmark.common.constant.RedisConstant;
|
|
||||||
import com.fanxb.bookmark.common.entity.MailInfo;
|
|
||||||
import com.fanxb.bookmark.common.entity.User;
|
|
||||||
import com.fanxb.bookmark.common.exception.FormDataException;
|
|
||||||
import com.fanxb.bookmark.common.util.*;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 类功能简述:
|
* 用户接口
|
||||||
* 类功能详述:
|
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/5 17:39
|
* @date 2021/3/11
|
||||||
*/
|
**/
|
||||||
@Service
|
public interface UserService {
|
||||||
public class UserService {
|
static final String DEFAULT_ICON = "/favicon.ico";
|
||||||
|
|
||||||
private static final String DEFAULT_ICON = "/favicon.ico";
|
|
||||||
/**
|
/**
|
||||||
* 短期jwt失效时间
|
* 短期jwt失效时间
|
||||||
*/
|
*/
|
||||||
private static final long SHORT_EXPIRE_TIME = 2 * 60 * 60 * 1000;
|
static final long SHORT_EXPIRE_TIME = 2 * 60 * 60 * 1000;
|
||||||
/**
|
/**
|
||||||
* 长期jwt失效时间
|
* 长期jwt失效时间
|
||||||
*/
|
*/
|
||||||
private static final long LONG_EXPIRE_TIME = 30L * TimeUtil.DAY_MS;
|
static final long LONG_EXPIRE_TIME = 30L * TimeUtil.DAY_MS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 头像文件大小限制 单位:KB
|
* 头像文件大小限制 单位:KB
|
||||||
*/
|
*/
|
||||||
private static final int ICON_SIZE = 200;
|
static final int ICON_SIZE = 200;
|
||||||
|
|
||||||
@Autowired
|
/***
|
||||||
private UserDao userDao;
|
* 获取一个可用的用户名
|
||||||
@Autowired
|
|
||||||
private StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 向目标发送验证码
|
|
||||||
*
|
|
||||||
* @param email 目标
|
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/5 17:48
|
|
||||||
*/
|
|
||||||
public void sendAuthCode(String email) {
|
|
||||||
MailInfo info = new MailInfo();
|
|
||||||
info.setSubject("签签世界注册验证码");
|
|
||||||
String code = StringUtil.getRandomString(6, 2);
|
|
||||||
info.setContent("欢迎注册 签签世界 ,本次验证码");
|
|
||||||
info.setContent(code + " 是您的验证码,注意验证码有效期为15分钟哦!");
|
|
||||||
info.setReceiver(email);
|
|
||||||
if (Constant.isDev) {
|
|
||||||
code = "123456";
|
|
||||||
} else {
|
|
||||||
MailUtil.sendTextMail(info);
|
|
||||||
}
|
|
||||||
RedisUtil.set(Constant.authCodeKey(email), code, Constant.AUTH_CODE_EXPIRE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 用户注册
|
|
||||||
*
|
|
||||||
* @param body 注册表单
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/6 11:30
|
|
||||||
*/
|
|
||||||
public LoginRes register(RegisterBody body) {
|
|
||||||
User user = userDao.selectByUsernameOrEmail(body.getUsername(), body.getEmail());
|
|
||||||
if (user != null) {
|
|
||||||
if (user.getUsername().equals(body.getUsername())) {
|
|
||||||
throw new FormDataException("用户名已经被注册");
|
|
||||||
}
|
|
||||||
if (user.getEmail().equals(body.getEmail())) {
|
|
||||||
throw new FormDataException("邮箱已经被注册");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
user = new User();
|
|
||||||
user.setUsername(body.getUsername());
|
|
||||||
user.setEmail(body.getEmail());
|
|
||||||
user.setIcon(DEFAULT_ICON);
|
|
||||||
user.setPassword(HashUtil.sha1(HashUtil.md5(body.getPassword())));
|
|
||||||
user.setCreateTime(System.currentTimeMillis());
|
|
||||||
user.setLastLoginTime(System.currentTimeMillis());
|
|
||||||
user.setVersion(0);
|
|
||||||
userDao.addOne(user);
|
|
||||||
Map<String, String> data = new HashMap<>(1);
|
|
||||||
data.put("userId", String.valueOf(user.getUserId()));
|
|
||||||
String token = JwtUtil.encode(data, Constant.jwtSecret, LONG_EXPIRE_TIME);
|
|
||||||
return new LoginRes(user, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 登录
|
|
||||||
*
|
|
||||||
* @param body 登录表单
|
|
||||||
* @return LoginRes
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/6 16:37
|
|
||||||
*/
|
|
||||||
public LoginRes login(LoginBody body) {
|
|
||||||
String key = RedisConstant.getUserFailCountKey(body.getStr());
|
|
||||||
String count = redisTemplate.opsForValue().get(key);
|
|
||||||
if (count != null && Integer.parseInt(count) >= 5) {
|
|
||||||
redisTemplate.expire(key, 30, TimeUnit.MINUTES);
|
|
||||||
throw new FormDataException("您已连续输错密码5次,请30分钟后再试,或联系管理员处理");
|
|
||||||
}
|
|
||||||
User userInfo = userDao.selectByUsernameOrEmail(body.getStr(), body.getStr());
|
|
||||||
if (userInfo == null || !HashUtil.sha1(HashUtil.md5(body.getPassword())).equals(userInfo.getPassword())) {
|
|
||||||
redisTemplate.opsForValue().set(key, count == null ? "1" : String.valueOf(Integer.parseInt(count) + 1), 30, TimeUnit.MINUTES);
|
|
||||||
throw new FormDataException("账号密码错误");
|
|
||||||
}
|
|
||||||
redisTemplate.delete(key);
|
|
||||||
Map<String, String> data = new HashMap<>(1);
|
|
||||||
data.put("userId", String.valueOf(userInfo.getUserId()));
|
|
||||||
String token = JwtUtil.encode(data, Constant.jwtSecret, body.isRememberMe() ? LONG_EXPIRE_TIME : SHORT_EXPIRE_TIME);
|
|
||||||
LoginRes res = new LoginRes();
|
|
||||||
res.setToken(token);
|
|
||||||
res.setUser(userInfo);
|
|
||||||
userDao.updateLastLoginTime(System.currentTimeMillis(), userInfo.getUserId());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 重置密码
|
|
||||||
*
|
|
||||||
* @param body 重置密码 由于参数和注册差不多,所以用同一个表单
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/9 19:59
|
|
||||||
*/
|
|
||||||
public void resetPassword(RegisterBody body) {
|
|
||||||
User user = userDao.selectByUsernameOrEmail(body.getEmail(), body.getEmail());
|
|
||||||
if (user == null) {
|
|
||||||
throw new FormDataException("用户不存在");
|
|
||||||
}
|
|
||||||
String codeKey = Constant.authCodeKey(body.getEmail());
|
|
||||||
String realCode = RedisUtil.get(codeKey, String.class);
|
|
||||||
if (StringUtil.isEmpty(realCode) || (!realCode.equals(body.getAuthCode()))) {
|
|
||||||
throw new FormDataException("验证码错误");
|
|
||||||
}
|
|
||||||
RedisUtil.delete(codeKey);
|
|
||||||
String newPassword = HashUtil.getPassword(body.getPassword());
|
|
||||||
userDao.resetPassword(newPassword, body.getEmail());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 根据userId获取用户信息
|
|
||||||
*
|
|
||||||
* @param userId userId
|
|
||||||
* @return com.fanxb.bookmark.common.entity.User
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/30 15:57
|
|
||||||
*/
|
|
||||||
public User getUserInfo(int userId) {
|
|
||||||
return userDao.selectByUserId(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改用户头像
|
|
||||||
*
|
|
||||||
* @param file file
|
|
||||||
* @return 访问路径
|
|
||||||
*/
|
|
||||||
public String updateIcon(MultipartFile file) throws Exception {
|
|
||||||
if (file.getSize() / NumberConstant.K_SIZE > ICON_SIZE) {
|
|
||||||
throw new FormDataException("文件大小超过限制");
|
|
||||||
}
|
|
||||||
int userId = UserContextHolder.get().getUserId();
|
|
||||||
String fileName = file.getOriginalFilename();
|
|
||||||
assert fileName != null;
|
|
||||||
String path = Paths.get(FileConstant.iconPath, userId + "." + System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf("."))).toString();
|
|
||||||
Path realPath = Paths.get(Constant.fileSavePath, path);
|
|
||||||
FileUtil.ensurePathExist(realPath.getParent().toString());
|
|
||||||
file.transferTo(realPath);
|
|
||||||
path = File.separator + path;
|
|
||||||
userDao.updateUserIcon(userId, path);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 功能描述: 密码校验,校验成功返回一个actionId,以执行敏感操作
|
|
||||||
*
|
|
||||||
* @param password password
|
|
||||||
* @return java.lang.String
|
* @return java.lang.String
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
String createNewUsername();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户的version
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/11/11 23:41
|
* @date 2021/3/11
|
||||||
*/
|
**/
|
||||||
public String checkPassword(String password) {
|
int getCurrentUserVersion(int userId);
|
||||||
int userId = UserContextHolder.get().getUserId();
|
|
||||||
String pass = HashUtil.getPassword(password);
|
|
||||||
User user = userDao.selectByUserId(userId);
|
|
||||||
if (!user.getPassword().equals(pass)) {
|
|
||||||
throw new FormDataException("密码错误,请重试");
|
|
||||||
}
|
|
||||||
String actionId = UUID.randomUUID().toString().replaceAll("-", "");
|
|
||||||
String key = RedisConstant.getPasswordCheckKey(userId, actionId);
|
|
||||||
RedisUtil.set(key, "1", 5 * 60 * 1000);
|
|
||||||
return actionId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,116 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import com.fanxb.bookmark.business.user.service.OAuthService;
|
||||||
|
import com.fanxb.bookmark.business.user.service.UserService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.OAuthBody;
|
||||||
|
import com.fanxb.bookmark.common.constant.Constant;
|
||||||
|
import com.fanxb.bookmark.common.entity.User;
|
||||||
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
|
import com.fanxb.bookmark.common.util.HttpUtil;
|
||||||
|
import com.fanxb.bookmark.common.util.JwtUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fanxb.bookmark.business.user.service.UserService.LONG_EXPIRE_TIME;
|
||||||
|
import static com.fanxb.bookmark.business.user.service.UserService.SHORT_EXPIRE_TIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth交互类
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/10
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class OAuthServiceImpl implements OAuthService {
|
||||||
|
|
||||||
|
@Value("${OAuth.github.clientId}")
|
||||||
|
private String githubClientId;
|
||||||
|
@Value("${OAuth.github.secret}")
|
||||||
|
private String githubSecret;
|
||||||
|
private final UserDao userDao;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public OAuthServiceImpl(UserDao userDao, UserService userService) {
|
||||||
|
this.userDao = userDao;
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String oAuthCheck(OAuthBody body) {
|
||||||
|
User current, other = new User();
|
||||||
|
if (StrUtil.equals(body.getType(), OAuthBody.GITHUB)) {
|
||||||
|
Map<String, String> header = new HashMap<>(2);
|
||||||
|
header.put("accept", "application/json");
|
||||||
|
String url = "https://github.com/login/oauth/access_token?client_id=" + githubClientId + "&client_secret=" + githubSecret + "&code=" + body.getCode();
|
||||||
|
JSONObject obj = HttpUtil.get(url, header);
|
||||||
|
String accessToken = obj.getString("access_token");
|
||||||
|
if (StrUtil.isEmpty(accessToken)) {
|
||||||
|
throw new CustomException("github登陆失败,请稍后重试");
|
||||||
|
}
|
||||||
|
header.put("Authorization", "token " + accessToken);
|
||||||
|
JSONObject userInfo = HttpUtil.get("https://api.github.com/user", header);
|
||||||
|
other.setGithubId(userInfo.getLong("id"));
|
||||||
|
if (other.getGithubId() == null) {
|
||||||
|
log.error("github返回异常:{}", userInfo.toString());
|
||||||
|
throw new CustomException("登陆异常,请稍后重试");
|
||||||
|
}
|
||||||
|
other.setEmail(userInfo.getString("email"));
|
||||||
|
other.setIcon(userInfo.getString("avatar_url"));
|
||||||
|
other.setUsername(userInfo.getString("login"));
|
||||||
|
current = userDao.selectByUserIdOrGithubId(null, other.getGithubId());
|
||||||
|
if (current == null) {
|
||||||
|
current = userDao.selectByUsernameOrEmail(null, other.getEmail());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new CustomException("不支持的登陆方式" + body.getType());
|
||||||
|
}
|
||||||
|
User newest = dealOAuth(current, other);
|
||||||
|
return JwtUtil.encode(Collections.singletonMap("userId", String.valueOf(newest.getUserId())), Constant.jwtSecret
|
||||||
|
, body.isRememberMe() ? LONG_EXPIRE_TIME : SHORT_EXPIRE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO 方法描述
|
||||||
|
*
|
||||||
|
* @param current 当前是否存在该用户
|
||||||
|
* @param other 第三方获取的数据
|
||||||
|
* @return User 最新的用户信息
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
private User dealOAuth(User current, User other) {
|
||||||
|
if (current == null) {
|
||||||
|
//判断用户名是否可用
|
||||||
|
if (userDao.usernameExist(other.getUsername())) {
|
||||||
|
other.setUsername(userService.createNewUsername());
|
||||||
|
}
|
||||||
|
other.setPassword("");
|
||||||
|
other.setCreateTime(System.currentTimeMillis());
|
||||||
|
other.setLastLoginTime(System.currentTimeMillis());
|
||||||
|
other.setVersion(0);
|
||||||
|
userDao.addOne(other);
|
||||||
|
return other;
|
||||||
|
} else {
|
||||||
|
if (!current.getEmail().equals(other.getEmail()) || !current.getGithubId().equals(other.getGithubId())) {
|
||||||
|
current.setEmail(other.getEmail());
|
||||||
|
current.setGithubId(other.getGithubId());
|
||||||
|
userDao.updateEmailAndGithubId(current);
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,219 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.fanxb.bookmark.business.user.constant.FileConstant;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import com.fanxb.bookmark.business.user.service.UserService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.LoginBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.LoginRes;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.RegisterBody;
|
||||||
|
import com.fanxb.bookmark.common.constant.Constant;
|
||||||
|
import com.fanxb.bookmark.common.constant.NumberConstant;
|
||||||
|
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.MailInfo;
|
||||||
|
import com.fanxb.bookmark.common.entity.User;
|
||||||
|
import com.fanxb.bookmark.common.exception.FormDataException;
|
||||||
|
import com.fanxb.bookmark.common.util.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类功能简述:
|
||||||
|
* 类功能详述:
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/5 17:39
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class UserServiceImpl implements UserService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserDao userDao;
|
||||||
|
@Autowired
|
||||||
|
private StringRedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 向目标发送验证码
|
||||||
|
*
|
||||||
|
* @param email 目标
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/5 17:48
|
||||||
|
*/
|
||||||
|
public void sendAuthCode(String email) {
|
||||||
|
MailInfo info = new MailInfo();
|
||||||
|
info.setSubject("签签世界注册验证码");
|
||||||
|
String code = StringUtil.getRandomString(6, 2);
|
||||||
|
info.setContent("欢迎注册 签签世界 ,本次验证码");
|
||||||
|
info.setContent(code + " 是您的验证码,注意验证码有效期为15分钟哦!");
|
||||||
|
info.setReceiver(email);
|
||||||
|
if (Constant.isDev) {
|
||||||
|
code = "123456";
|
||||||
|
} else {
|
||||||
|
MailUtil.sendTextMail(info);
|
||||||
|
}
|
||||||
|
RedisUtil.set(Constant.authCodeKey(email), code, Constant.AUTH_CODE_EXPIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 用户注册
|
||||||
|
*
|
||||||
|
* @param body 注册表单
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/6 11:30
|
||||||
|
*/
|
||||||
|
public String register(RegisterBody body) {
|
||||||
|
User user = userDao.selectByUsernameOrEmail(body.getUsername(), body.getEmail());
|
||||||
|
if (user != null) {
|
||||||
|
if (user.getUsername().equals(body.getUsername())) {
|
||||||
|
throw new FormDataException("用户名已经被注册");
|
||||||
|
}
|
||||||
|
if (user.getEmail().equals(body.getEmail())) {
|
||||||
|
throw new FormDataException("邮箱已经被注册");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user = new User();
|
||||||
|
user.setUsername(body.getUsername());
|
||||||
|
user.setEmail(body.getEmail());
|
||||||
|
user.setIcon(DEFAULT_ICON);
|
||||||
|
user.setPassword(HashUtil.sha1(HashUtil.md5(body.getPassword())));
|
||||||
|
user.setCreateTime(System.currentTimeMillis());
|
||||||
|
user.setLastLoginTime(System.currentTimeMillis());
|
||||||
|
user.setVersion(0);
|
||||||
|
userDao.addOne(user);
|
||||||
|
Map<String, String> data = new HashMap<>(1);
|
||||||
|
data.put("userId", String.valueOf(user.getUserId()));
|
||||||
|
return JwtUtil.encode(data, Constant.jwtSecret, LONG_EXPIRE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 登录
|
||||||
|
*
|
||||||
|
* @param body 登录表单
|
||||||
|
* @return string
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/6 16:37
|
||||||
|
*/
|
||||||
|
public String login(LoginBody body) {
|
||||||
|
String key = RedisConstant.getUserFailCountKey(body.getStr());
|
||||||
|
String count = redisTemplate.opsForValue().get(key);
|
||||||
|
if (count != null && Integer.parseInt(count) >= 5) {
|
||||||
|
redisTemplate.expire(key, 30, TimeUnit.MINUTES);
|
||||||
|
throw new FormDataException("您已连续输错密码5次,请30分钟后再试,或联系管理员处理");
|
||||||
|
}
|
||||||
|
User userInfo = userDao.selectByUsernameOrEmail(body.getStr(), body.getStr());
|
||||||
|
if (userInfo == null || StrUtil.isEmpty(userInfo.getPassword()) || !HashUtil.sha1(HashUtil.md5(body.getPassword())).equals(userInfo.getPassword())) {
|
||||||
|
redisTemplate.opsForValue().set(key, count == null ? "1" : String.valueOf(Integer.parseInt(count) + 1), 30, TimeUnit.MINUTES);
|
||||||
|
throw new FormDataException("账号密码错误");
|
||||||
|
}
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
userDao.updateLastLoginTime(System.currentTimeMillis(), userInfo.getUserId());
|
||||||
|
return JwtUtil.encode(Collections.singletonMap("userId", String.valueOf(userInfo.getUserId())), Constant.jwtSecret
|
||||||
|
, body.isRememberMe() ? LONG_EXPIRE_TIME : SHORT_EXPIRE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 重置密码
|
||||||
|
*
|
||||||
|
* @param body 重置密码 由于参数和注册差不多,所以用同一个表单
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/9 19:59
|
||||||
|
*/
|
||||||
|
public void resetPassword(RegisterBody body) {
|
||||||
|
User user = userDao.selectByUsernameOrEmail(body.getEmail(), body.getEmail());
|
||||||
|
if (user == null) {
|
||||||
|
throw new FormDataException("用户不存在");
|
||||||
|
}
|
||||||
|
String codeKey = Constant.authCodeKey(body.getEmail());
|
||||||
|
String realCode = RedisUtil.get(codeKey, String.class);
|
||||||
|
if (StringUtil.isEmpty(realCode) || (!realCode.equals(body.getAuthCode()))) {
|
||||||
|
throw new FormDataException("验证码错误");
|
||||||
|
}
|
||||||
|
RedisUtil.delete(codeKey);
|
||||||
|
String newPassword = HashUtil.getPassword(body.getPassword());
|
||||||
|
userDao.resetPassword(newPassword, body.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 根据userId获取用户信息
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @return com.fanxb.bookmark.common.entity.User
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/30 15:57
|
||||||
|
*/
|
||||||
|
public User getUserInfo(int userId) {
|
||||||
|
User user = userDao.selectByUserIdOrGithubId(userId, null);
|
||||||
|
user.setNoPassword(StrUtil.isEmpty(user.getPassword()));
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户头像
|
||||||
|
*
|
||||||
|
* @param file file
|
||||||
|
* @return 访问路径
|
||||||
|
*/
|
||||||
|
public String updateIcon(MultipartFile file) throws Exception {
|
||||||
|
if (file.getSize() / NumberConstant.K_SIZE > ICON_SIZE) {
|
||||||
|
throw new FormDataException("文件大小超过限制");
|
||||||
|
}
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
String fileName = file.getOriginalFilename();
|
||||||
|
assert fileName != null;
|
||||||
|
String path = Paths.get(FileConstant.iconPath, userId + "." + System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf("."))).toString();
|
||||||
|
Path realPath = Paths.get(Constant.fileSavePath, path);
|
||||||
|
FileUtil.ensurePathExist(realPath.getParent().toString());
|
||||||
|
file.transferTo(realPath);
|
||||||
|
path = File.separator + path;
|
||||||
|
userDao.updateUserIcon(userId, path);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 密码校验,校验成功返回一个actionId,以执行敏感操作
|
||||||
|
*
|
||||||
|
* @param password password
|
||||||
|
* @return java.lang.String
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/11/11 23:41
|
||||||
|
*/
|
||||||
|
public String checkPassword(String password) {
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
String pass = HashUtil.getPassword(password);
|
||||||
|
User user = userDao.selectByUserIdOrGithubId(userId, null);
|
||||||
|
if (!user.getPassword().equals(pass)) {
|
||||||
|
throw new FormDataException("密码错误,请重试");
|
||||||
|
}
|
||||||
|
String actionId = UUID.randomUUID().toString().replaceAll("-", "");
|
||||||
|
String key = RedisConstant.getPasswordCheckKey(userId, actionId);
|
||||||
|
RedisUtil.set(key, "1", 5 * 60 * 1000);
|
||||||
|
return actionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createNewUsername() {
|
||||||
|
while (true) {
|
||||||
|
String name = RandomUtil.randomString(8);
|
||||||
|
if (!userDao.usernameExist(name)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCurrentUserVersion(int userId) {
|
||||||
|
return userDao.getUserVersion(userId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登陆入参
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/10
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
public class OAuthBody {
|
||||||
|
public static final String GITHUB = "github";
|
||||||
|
/**
|
||||||
|
* 类别
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
/**
|
||||||
|
* 识别码
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
/**
|
||||||
|
* 是否保持登陆
|
||||||
|
*/
|
||||||
|
private boolean rememberMe;
|
||||||
|
}
|
@ -10,17 +10,10 @@
|
|||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<select id="selectByUsernameOrEmail" resultType="com.fanxb.bookmark.common.entity.User">
|
<select id="selectByUsernameOrEmail" resultType="com.fanxb.bookmark.common.entity.User">
|
||||||
select
|
select *
|
||||||
userId,
|
|
||||||
username,
|
|
||||||
email,
|
|
||||||
icon,
|
|
||||||
password,
|
|
||||||
createTime,
|
|
||||||
lastLoginTime,
|
|
||||||
version
|
|
||||||
from user
|
from user
|
||||||
where username = #{name} or email = #{email}
|
where username = #{name}
|
||||||
|
or email = #{email}
|
||||||
limit 1
|
limit 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@ -36,10 +29,11 @@
|
|||||||
where email = #{email}
|
where email = #{email}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<select id="selectByUserId" resultType="com.fanxb.bookmark.common.entity.User">
|
<select id="selectByUserIdOrGithubId" resultType="com.fanxb.bookmark.common.entity.User">
|
||||||
select *
|
select *
|
||||||
from user
|
from user
|
||||||
where userId = #{userId}
|
where userId = #{userId}
|
||||||
|
or githubId = #{githubId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,10 +19,18 @@ import java.util.Map;
|
|||||||
public class User {
|
public class User {
|
||||||
|
|
||||||
private int userId;
|
private int userId;
|
||||||
|
/**
|
||||||
|
* 第三方github登陆id,-1说明非github登陆
|
||||||
|
*/
|
||||||
|
private Long githubId;
|
||||||
private String username;
|
private String username;
|
||||||
private String email;
|
private String email;
|
||||||
private String newEmail;
|
private String newEmail;
|
||||||
private String icon;
|
private String icon;
|
||||||
|
/**
|
||||||
|
* 是否未设置密码
|
||||||
|
*/
|
||||||
|
private Boolean noPassword;
|
||||||
@JSONField(serialize = false)
|
@JSONField(serialize = false)
|
||||||
private String password;
|
private String password;
|
||||||
private long createTime;
|
private long createTime;
|
||||||
@ -34,4 +42,5 @@ public class User {
|
|||||||
* 书签同步版本
|
* 书签同步版本
|
||||||
*/
|
*/
|
||||||
private int version;
|
private int version;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
package com.fanxb.bookmark.common.util;
|
package com.fanxb.bookmark.common.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.fanxb.bookmark.common.exception.CustomException;
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Proxy;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -17,13 +23,30 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/4/4 15:53
|
* @date 2019/4/4 15:53
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
public class HttpUtil {
|
public class HttpUtil {
|
||||||
|
@Value("${proxy.ip}")
|
||||||
|
private String proxyIp;
|
||||||
|
@Value("${proxy.port}")
|
||||||
|
private int proxyPort;
|
||||||
|
|
||||||
private static final int IP_LENGTH = 15;
|
private static final int IP_LENGTH = 15;
|
||||||
|
|
||||||
public static final OkHttpClient CLIENT = new OkHttpClient.Builder().connectTimeout(3, TimeUnit.SECONDS)
|
private static OkHttpClient CLIENT;
|
||||||
.readTimeout(300, TimeUnit.SECONDS).build();
|
|
||||||
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
|
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||||
|
if (StrUtil.isNotBlank(proxyIp)) {
|
||||||
|
builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyIp, proxyPort)));
|
||||||
|
}
|
||||||
|
CLIENT = builder.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 功能描述: get
|
* 功能描述: get
|
||||||
*
|
*
|
||||||
@ -142,6 +165,8 @@ public class HttpUtil {
|
|||||||
String str = res.body().string();
|
String str = res.body().string();
|
||||||
if (typeClass.getCanonicalName().equals(JSONObject.class.getCanonicalName())) {
|
if (typeClass.getCanonicalName().equals(JSONObject.class.getCanonicalName())) {
|
||||||
return (T) JSONObject.parseObject(str);
|
return (T) JSONObject.parseObject(str);
|
||||||
|
} else if (typeClass.getCanonicalName().equals(String.class.getCanonicalName())) {
|
||||||
|
return (T) str;
|
||||||
} else {
|
} else {
|
||||||
return (T) JSONArray.parseArray(str);
|
return (T) JSONArray.parseArray(str);
|
||||||
}
|
}
|
||||||
|
@ -76,3 +76,18 @@ fileSavePath: ./
|
|||||||
|
|
||||||
# 服务部署地址
|
# 服务部署地址
|
||||||
serviceAddress: http://localhost
|
serviceAddress: http://localhost
|
||||||
|
|
||||||
|
# 第三方登陆相关
|
||||||
|
OAuth:
|
||||||
|
github:
|
||||||
|
# 客户端id
|
||||||
|
clientId:
|
||||||
|
# 客户端密钥
|
||||||
|
secret:
|
||||||
|
|
||||||
|
# 网络代理(有配置就用代理,未配置不使用代理)
|
||||||
|
proxy:
|
||||||
|
ip:
|
||||||
|
port:
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
INSERT INTO `bookmark`.`url`(`method`, `url`, `type`) VALUES ('POST', '/user/oAuthLogin', 0);
|
@ -0,0 +1,14 @@
|
|||||||
|
alter table user
|
||||||
|
add githubId bigint default -1 not null comment '-1说明未使用github登陆' after userId;
|
||||||
|
|
||||||
|
create unique index email_index
|
||||||
|
on user (email);
|
||||||
|
|
||||||
|
create index githubIdIndex
|
||||||
|
on user (githubId);
|
||||||
|
|
||||||
|
create index new_email_index
|
||||||
|
on user (newEmail);
|
||||||
|
|
||||||
|
create unique index username_index
|
||||||
|
on user (username);
|
1
bookmark_front/.env.development
Normal file
1
bookmark_front/.env.development
Normal file
@ -0,0 +1 @@
|
|||||||
|
VUE_APP_GITHUB_CLIENT_ID=
|
1
bookmark_front/.env.production
Normal file
1
bookmark_front/.env.production
Normal file
@ -0,0 +1 @@
|
|||||||
|
VUE_APP_GITHUB_CLIENT_ID=
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "App"
|
name: "App",
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -25,5 +25,6 @@ body {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
color: #2c3e50;
|
color: #2c3e50;
|
||||||
|
font-size: 0.16rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main" v-if="userInfo">
|
||||||
<a class="ico" href="/"><img src="/static/img/bookmarkLogo.png" /></a>
|
<a class="ico" href="/"><img src="/static/img/bookmarkLogo.png" /></a>
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<div class="user">
|
<div class="user">
|
||||||
@ -31,7 +31,7 @@ export default {
|
|||||||
await this.$store.dispatch("globalConfig/clear");
|
await this.$store.dispatch("globalConfig/clear");
|
||||||
this.$router.replace("/public/login");
|
this.$router.replace("/public/login");
|
||||||
} else if (key === "personSpace") {
|
} else if (key === "personSpace") {
|
||||||
this.$router.push("personSpace/userInfo");
|
this.$router.push("/personSpace/userInfo");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -8,6 +8,7 @@ import Public from "../views/public/Public.vue";
|
|||||||
import Login from "../views/public/pages/Login.vue";
|
import Login from "../views/public/pages/Login.vue";
|
||||||
import Register from "../views/public/pages/Register.vue";
|
import Register from "../views/public/pages/Register.vue";
|
||||||
import ResetPassword from "../views/public/pages/ResetPassword.vue";
|
import ResetPassword from "../views/public/pages/ResetPassword.vue";
|
||||||
|
import GithubOauth from "../views/public/pages/oauth/Github.vue";
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
@ -47,12 +48,18 @@ const routes = [
|
|||||||
path: "resetPassword",
|
path: "resetPassword",
|
||||||
name: "ResetPassword",
|
name: "ResetPassword",
|
||||||
component: ResetPassword
|
component: ResetPassword
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "oauth/github",
|
||||||
|
name: "GithubRedirect",
|
||||||
|
component: GithubOauth
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = new VueRouter({
|
const router = new VueRouter({
|
||||||
|
mode: "history",
|
||||||
routes
|
routes
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import localforage from "localforage";
|
import localforage from "localforage";
|
||||||
import HttpUtil from "../../util/HttpUtil";
|
import HttpUtil from "../../util/HttpUtil";
|
||||||
|
const USER_INFO = "userInfo";
|
||||||
|
const TOKEN = "token";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 存储全局配置
|
* 存储全局配置
|
||||||
*/
|
*/
|
||||||
@ -7,11 +10,11 @@ const state = {
|
|||||||
/**
|
/**
|
||||||
* 用户信息
|
* 用户信息
|
||||||
*/
|
*/
|
||||||
userInfo: {},
|
[USER_INFO]: {},
|
||||||
/**
|
/**
|
||||||
* token
|
* token
|
||||||
*/
|
*/
|
||||||
token: null,
|
[TOKEN]: null,
|
||||||
/**
|
/**
|
||||||
* 是否已经初始化完成,避免多次重复初始化
|
* 是否已经初始化完成,避免多次重复初始化
|
||||||
*/
|
*/
|
||||||
@ -30,36 +33,43 @@ const actions = {
|
|||||||
if (context.state.isInit) {
|
if (context.state.isInit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.commit("setUserInfo", await localforage.getItem("userInfo"));
|
const token = await localforage.getItem(TOKEN);
|
||||||
const token = await localforage.getItem("token");
|
await context.dispatch("setToken", token);
|
||||||
window.token = token;
|
|
||||||
context.commit("setToken", token);
|
let userInfo = await localforage.getItem(USER_INFO);
|
||||||
|
if (userInfo === null || userInfo === "") {
|
||||||
|
await context.dispatch("refreshUserInfo");
|
||||||
|
} else {
|
||||||
|
context.commit(USER_INFO, userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
context.commit("isInit", true);
|
context.commit("isInit", true);
|
||||||
context.commit("isPhone", /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent));
|
context.commit("isPhone", /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent));
|
||||||
},
|
},
|
||||||
async refreshUserInfo({ commit }) {
|
async refreshUserInfo({ commit }) {
|
||||||
let userInfo = await HttpUtil.get("/user/currentUserInfo");
|
let userInfo = await HttpUtil.get("/user/currentUserInfo");
|
||||||
await localforage.setItem("userInfo", userInfo);
|
await localforage.setItem(USER_INFO, userInfo);
|
||||||
commit("setUserInfo", userInfo);
|
commit(USER_INFO, userInfo);
|
||||||
|
},
|
||||||
|
async setToken({ commit }, token) {
|
||||||
|
await localforage.setItem(TOKEN, token);
|
||||||
|
commit(TOKEN, token);
|
||||||
},
|
},
|
||||||
//登出清除数据
|
//登出清除数据
|
||||||
async clear(context) {
|
async clear(context) {
|
||||||
await localforage.removeItem("userInfo");
|
await localforage.removeItem("userInfo");
|
||||||
await localforage.removeItem("token");
|
await localforage.removeItem("token");
|
||||||
delete window.token;
|
context.commit(USER_INFO, null);
|
||||||
context.commit("setUserInfo", {});
|
context.commit(TOKEN, null);
|
||||||
context.commit("setToken", null);
|
context.commit("isInit", false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
setUserInfo(state, userInfo) {
|
userInfo(state, userInfo) {
|
||||||
localforage.setItem("userInfo", userInfo);
|
|
||||||
state.userInfo = userInfo;
|
state.userInfo = userInfo;
|
||||||
},
|
},
|
||||||
setToken(state, token) {
|
token(state, token) {
|
||||||
localforage.setItem("token", token);
|
|
||||||
window.token = token;
|
|
||||||
state.token = token;
|
state.token = token;
|
||||||
},
|
},
|
||||||
isInit(state, isInit) {
|
isInit(state, isInit) {
|
||||||
|
@ -39,14 +39,14 @@ const getters = {
|
|||||||
const actions = {
|
const actions = {
|
||||||
//从缓存初始化数据
|
//从缓存初始化数据
|
||||||
async init(context) {
|
async init(context) {
|
||||||
if (context.state.isInit) {
|
if (context.state.isInit || context.state.isIniting) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.commit("isIniting", true);
|
context.commit("isIniting", true);
|
||||||
let userInfo = await httpUtil.get("/user/currentUserInfo");
|
let realVersion = await httpUtil.get("/user/version");
|
||||||
let data = await localforage.getItem(TOTAL_TREE_DATA);
|
let data = await localforage.getItem(TOTAL_TREE_DATA);
|
||||||
let version = await localforage.getItem(VERSION);
|
let version = await localforage.getItem(VERSION);
|
||||||
if (!data || userInfo.version > version) {
|
if (!data || realVersion > version) {
|
||||||
await context.dispatch("refresh");
|
await context.dispatch("refresh");
|
||||||
} else {
|
} else {
|
||||||
context.commit(TOTAL_TREE_DATA, data);
|
context.commit(TOTAL_TREE_DATA, data);
|
||||||
@ -85,8 +85,8 @@ const actions = {
|
|||||||
item1.scopedSlots = { title: "nodeTitle" };
|
item1.scopedSlots = { title: "nodeTitle" };
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
let userInfo = await httpUtil.get("/user/currentUserInfo");
|
let version = await httpUtil.get("/user/version");
|
||||||
await context.dispatch("updateVersion", userInfo.version);
|
await context.dispatch("updateVersion", version);
|
||||||
context.commit(TOTAL_TREE_DATA, treeData);
|
context.commit(TOTAL_TREE_DATA, treeData);
|
||||||
await localforage.setItem(TOTAL_TREE_DATA, treeData);
|
await localforage.setItem(TOTAL_TREE_DATA, treeData);
|
||||||
},
|
},
|
||||||
@ -243,7 +243,7 @@ const actions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
totalTreeData(state, totalTreeData) {
|
[TOTAL_TREE_DATA]: (state, totalTreeData) => {
|
||||||
state.totalTreeData = totalTreeData;
|
state.totalTreeData = totalTreeData;
|
||||||
},
|
},
|
||||||
isInit(state, isInit) {
|
isInit(state, isInit) {
|
||||||
@ -253,7 +253,7 @@ const mutations = {
|
|||||||
state.isIniting = isIniting;
|
state.isIniting = isIniting;
|
||||||
},
|
},
|
||||||
|
|
||||||
version(state, version) {
|
[VERSION]: (state, version) => {
|
||||||
state[VERSION] = version;
|
state[VERSION] = version;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as http from "axios";
|
import * as http from "axios";
|
||||||
import { getToken } from "./UserUtil";
|
import vuex from "../store/index.js";
|
||||||
import router from "../router/index";
|
import router from "../router/index";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,7 +19,7 @@ async function request(url, method, params, body, isForm, redirect) {
|
|||||||
method,
|
method,
|
||||||
params,
|
params,
|
||||||
headers: {
|
headers: {
|
||||||
"jwt-token": await getToken()
|
"jwt-token": vuex.state.globalConfig.token
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (isForm) {
|
if (isForm) {
|
||||||
|
@ -1,26 +1,4 @@
|
|||||||
import localStore from "localforage";
|
|
||||||
// import HttpUtil from './HttpUtil.js';
|
|
||||||
const TOKEN = "token";
|
const TOKEN = "token";
|
||||||
// consts USER_INFO = "userInfo";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户token
|
|
||||||
*/
|
|
||||||
export async function getToken() {
|
|
||||||
if (!window.token) {
|
|
||||||
window.token = await localStore.getItem(TOKEN);
|
|
||||||
}
|
|
||||||
return window.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除用户token
|
|
||||||
*/
|
|
||||||
export async function clearToken() {
|
|
||||||
delete window.token;
|
|
||||||
await localStore.removeItem(TOKEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本地获取用户信息
|
* 本地获取用户信息
|
||||||
*/
|
*/
|
||||||
|
@ -52,10 +52,9 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
let userInfo = await httpUtil.get("/user/currentUserInfo");
|
let version = await httpUtil.get("/user/version");
|
||||||
this.$store.commit("globalConfig/setUserInfo", userInfo);
|
|
||||||
const _this = this;
|
const _this = this;
|
||||||
if (this.$store.state.treeData.version < userInfo.version) {
|
if (this.$store.state.treeData.version < version) {
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
this.$confirm({
|
this.$confirm({
|
||||||
title: "书签数据有更新,是否立即刷新?",
|
title: "书签数据有更新,是否立即刷新?",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<img class="ico" src="/static/img/bookmarkLogo.png" />
|
<img class="ico" src="/static/img/bookmarkLogo.png" />
|
||||||
<div class="main-body">
|
<div class="main-body">
|
||||||
<router-view />
|
<router-view />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -34,7 +35,7 @@ export default {
|
|||||||
width: 2rem;
|
width: 2rem;
|
||||||
}
|
}
|
||||||
.main-body {
|
.main-body {
|
||||||
width: 5rem;
|
min-width: 5rem;
|
||||||
min-height: 3.5rem;
|
min-height: 3.5rem;
|
||||||
background-color: @publicBgColor;
|
background-color: @publicBgColor;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Header current="login" />
|
<Header current="login" />
|
||||||
<div class="form">
|
<a-spin class="form" :delay="100" :spinning="loading">
|
||||||
<a-form-model ref="loginForm" :model="form" :rules="rules">
|
<a-form-model ref="loginForm" :model="form" :rules="rules">
|
||||||
<a-form-model-item prop="str" ref="str">
|
<a-form-model-item prop="str" ref="str">
|
||||||
<a-input v-model="form.str" placeholder="邮箱/用户名">
|
<a-input v-model="form.str" placeholder="邮箱/用户名">
|
||||||
@ -13,20 +13,24 @@
|
|||||||
<a-icon slot="prefix" type="password" style="color:rgba(0,0,0,.25)" />
|
<a-icon slot="prefix" type="password" style="color:rgba(0,0,0,.25)" />
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item prop="password">
|
|
||||||
<div class="reset">
|
<div class="reset">
|
||||||
<a-checkbox v-model="form.rememberMe">记住我</a-checkbox>
|
<a-checkbox v-model="form.rememberMe">记住我</a-checkbox>
|
||||||
<router-link to="resetPassword" replace>重置密码</router-link>
|
<router-link to="resetPassword" replace>重置密码</router-link>
|
||||||
</div>
|
</div>
|
||||||
</a-form-model-item>
|
|
||||||
|
|
||||||
<a-form-model-item>
|
<a-form-model-item>
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
<a-button type="primary" block @click="submit">登录</a-button>
|
<a-button type="primary" block @click="submit">登录</a-button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="thirdPart">
|
||||||
|
<span>第三方登陆</span>
|
||||||
|
<a-tooltip title="github登陆" class="oneIcon" placement="bottom">
|
||||||
|
<a-icon type="github" @click="toGithub" style="font-size:1.4em" />
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
</a-form-model>
|
</a-form-model>
|
||||||
</div>
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -34,52 +38,109 @@
|
|||||||
import Header from "@/components/public/Switch.vue";
|
import Header from "@/components/public/Switch.vue";
|
||||||
import httpUtil from "../../../util/HttpUtil.js";
|
import httpUtil from "../../../util/HttpUtil.js";
|
||||||
import { mapMutations } from "vuex";
|
import { mapMutations } from "vuex";
|
||||||
|
import HttpUtil from "../../../util/HttpUtil.js";
|
||||||
export default {
|
export default {
|
||||||
name: "Login",
|
name: "Login",
|
||||||
components: {
|
components: {
|
||||||
Header
|
Header,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
str: "",
|
str: "",
|
||||||
password: "",
|
password: "",
|
||||||
rememberMe: false
|
rememberMe: false,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
str: [
|
str: [
|
||||||
{ required: true, message: "请输入用户名", trigger: "blur" },
|
{ required: true, message: "请输入用户名", trigger: "blur" },
|
||||||
{ min: 1, max: 50, message: "最短1,最长50", trigger: "change" }
|
{ min: 1, max: 50, message: "最短1,最长50", trigger: "change" },
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||||
{ pattern: "^\\w{6,18}$", message: "密码为6-18位数字,字母,下划线组合", trigger: "change" }
|
{ pattern: "^\\w{6,18}$", message: "密码为6-18位数字,字母,下划线组合", trigger: "change" },
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
|
loading: false, //是否加载中
|
||||||
|
oauthLogining: false, //true:正在进行oauth后台操作
|
||||||
|
page: null, //oauth打开的页面实例
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
async created() {
|
||||||
|
let _this = this;
|
||||||
|
window.addEventListener("storage", this.storageDeal.bind(this));
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
window.removeEventListener("storage", this.storageDeal);
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations("globalConfig", ["setUserInfo", "setToken"]),
|
...mapMutations("globalConfig", ["setUserInfo", "setToken"]),
|
||||||
submit() {
|
submit() {
|
||||||
this.$refs.loginForm.validate(async status => {
|
this.$refs.loginForm.validate(async (status) => {
|
||||||
if (status) {
|
if (status) {
|
||||||
let res = await httpUtil.post("/user/login", null, this.form);
|
try {
|
||||||
this.setUserInfo(res.user);
|
this.loading = true;
|
||||||
this.$store.commit("globalConfig/setToken", res.token);
|
let token = await httpUtil.post("/user/login", null, this.form);
|
||||||
|
this.$store.dispatch("globalConfig/setToken", token);
|
||||||
this.$router.replace("/");
|
this.$router.replace("/");
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
toGithub() {
|
||||||
|
let redirect = location.origin + "/public/oauth/github";
|
||||||
|
let clientId = process.env.VUE_APP_GITHUB_CLIENT_ID;
|
||||||
|
this.page = window.open(`https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirect}`);
|
||||||
|
},
|
||||||
|
async storageDeal(e) {
|
||||||
|
console.log(e);
|
||||||
|
if (e.key === "oauthMessage") {
|
||||||
|
if (this.page != null) {
|
||||||
|
this.page.close();
|
||||||
}
|
}
|
||||||
|
localStorage.removeItem("oauthMessage");
|
||||||
|
await this.oauthLogin(e.newValue);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async oauthLogin(form) {
|
||||||
|
if (this.loading) {
|
||||||
|
console.error("正在请求中", form);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
form = JSON.parse(form);
|
||||||
|
if (!form.code) {
|
||||||
|
this.$message.error("您已拒绝,无法继续登陆");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
form.rememberMe = this.form.rememberMe;
|
||||||
|
let token = await HttpUtil.post("/user/oAuthLogin", null, form);
|
||||||
|
this.$store.dispatch("globalConfig/setToken", token);
|
||||||
|
this.$router.replace("/");
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.form {
|
.form {
|
||||||
margin: 0.3rem;
|
margin: 0.3rem;
|
||||||
|
margin-bottom: 0.1rem;
|
||||||
.reset {
|
.reset {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.thirdPart {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 1.2em;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -40,7 +40,7 @@ import httpUtil from "../../../util/HttpUtil.js";
|
|||||||
export default {
|
export default {
|
||||||
name: "Login",
|
name: "Login",
|
||||||
components: {
|
components: {
|
||||||
Header
|
Header,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
let repeatPass = (rule, value, cb) => {
|
let repeatPass = (rule, value, cb) => {
|
||||||
@ -57,41 +57,40 @@ export default {
|
|||||||
username: "",
|
username: "",
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
repeatPass: ""
|
repeatPass: "",
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
username: [
|
username: [
|
||||||
{ required: true, message: "请输入用户名", trigger: "blur" },
|
{ required: true, message: "请输入用户名", trigger: "blur" },
|
||||||
{ min: 1, max: 50, message: "最短1,最长50", trigger: "blur" }
|
{ min: 1, max: 50, message: "最短1,最长50", trigger: "blur" },
|
||||||
],
|
],
|
||||||
email: [
|
email: [
|
||||||
{
|
{
|
||||||
pattern: /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
pattern: /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
||||||
message: "请输入正确的邮箱",
|
message: "请输入正确的邮箱",
|
||||||
trigger: "change"
|
trigger: "change",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||||
{ pattern: "^\\w{6,18}$", message: "密码为6-18位数字,字母,下划线组合", trigger: "change" }
|
{ pattern: "^\\w{6,18}$", message: "密码为6-18位数字,字母,下划线组合", trigger: "change" },
|
||||||
],
|
],
|
||||||
repeatPass: [{ validator: repeatPass, trigger: "change" }]
|
repeatPass: [{ validator: repeatPass, trigger: "change" }],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit() {
|
submit() {
|
||||||
let _this = this;
|
let _this = this;
|
||||||
this.$refs.registerForm.validate(async status => {
|
this.$refs.registerForm.validate(async (status) => {
|
||||||
if (status) {
|
if (status) {
|
||||||
let res = await httpUtil.put("/user", null, _this.form);
|
let res = await httpUtil.put("/user", null, _this.form);
|
||||||
this.$store.commit("globalConfig/setUserInfo", res.user);
|
this.$store.dispatch("globalConfig/setToken", res);
|
||||||
this.$store.commit("globalConfig/setToken", res.token);
|
|
||||||
this.$router.replace("/");
|
this.$router.replace("/");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
27
bookmark_front/src/views/public/pages/oauth/Github.vue
Normal file
27
bookmark_front/src/views/public/pages/oauth/Github.vue
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<div class="github">处理中,请稍候。。。</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "GithubRedirect",
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
let body = {
|
||||||
|
type: "github",
|
||||||
|
code: this.$route.query.code,
|
||||||
|
};
|
||||||
|
localStorage.setItem("oauthMessage", JSON.stringify(body));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.github {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user