123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- /*
- * <<
- * Davinci
- * ==
- * Copyright (C) 2016 - 2019 EDP
- * ==
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * >>
- *
- */
- package edp.davinci.service.impl;
- import com.alibaba.druid.util.StringUtils;
- import com.alibaba.fastjson.JSONObject;
- import com.jayway.jsonpath.JsonPath;
- import edp.core.consts.Consts;
- import edp.core.enums.HttpCodeEnum;
- import edp.core.enums.MailContentTypeEnum;
- import edp.core.exception.NotFoundException;
- import edp.core.exception.ServerException;
- import edp.core.model.MailContent;
- import edp.core.utils.*;
- import edp.davinci.core.common.Constants;
- import edp.davinci.core.common.ErrorMsg;
- import edp.davinci.core.common.ResultMap;
- import edp.davinci.core.enums.CheckEntityEnum;
- import edp.davinci.core.enums.LockType;
- import edp.davinci.core.enums.UserDistinctType;
- import edp.davinci.core.enums.UserOrgRoleEnum;
- import edp.davinci.dao.OrganizationMapper;
- import edp.davinci.dao.RelUserOrganizationMapper;
- import edp.davinci.dao.UserMapper;
- import edp.davinci.dto.organizationDto.OrganizationInfo;
- import edp.davinci.dto.userDto.*;
- import edp.davinci.model.LdapPerson;
- import edp.davinci.model.Organization;
- import edp.davinci.model.RelUserOrganization;
- import edp.davinci.model.User;
- import edp.davinci.service.LdapService;
- import edp.davinci.service.UserService;
- import lombok.extern.slf4j.Slf4j;
- import org.mindrot.jbcrypt.BCrypt;
- import org.springframework.beans.BeanUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.core.env.Environment;
- import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
- import org.springframework.security.oauth2.core.user.OAuth2User;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.web.multipart.MultipartFile;
- import javax.servlet.http.HttpServletRequest;
- import java.util.*;
- import java.util.regex.Matcher;
- @Slf4j
- @Service("userService")
- public class UserServiceImpl extends BaseEntityService implements UserService {
- @Autowired
- private UserMapper userMapper;
- @Autowired
- private OrganizationMapper organizationMapper;
- @Autowired
- private RelUserOrganizationMapper relUserOrganizationMapper;
- @Autowired
- private TokenUtils tokenUtils;
- @Autowired
- private MailUtils mailUtils;
- @Autowired
- private FileUtils fileUtils;
- @Autowired
- private ServerUtils serverUtils;
- @Autowired
- private LdapService ldapService;
- @Autowired
- private Environment environment;
- private static final CheckEntityEnum entity = CheckEntityEnum.USER;
- private static final Long TOKEN_TIMEOUT_MILLIS = 10 * 60 * 1000L;
- /**
- * 用户是否存在
- *
- * @param name
- * @param scopeId
- * @return
- */
- @Override
- public boolean isExist(String name, Long id, Long scopeId) {
- Long userId = userMapper.getIdByName(name);
- if (null != id && null != userId) {
- return !id.equals(userId);
- }
- return null != userId && userId.longValue() > 0L;
- }
- /**
- * 用户注册接口
- *
- * @param userRegist
- * @return
- */
- @Override
- @Transactional
- public User regist(UserRegist userRegist) throws ServerException {
- String username = userRegist.getUsername();
- //用户名是否已经注册
- if (isExist(username, null, null)) {
- log.info("The username({}) has been registered", username);
- throw new ServerException("The username:" + username + " has been registered");
- }
- String email = userRegist.getEmail();
- //邮箱是否已经注册
- // if (isExist(email, null, null)) {
- // log.info("The email({}) has been registered", email);
- // throw new ServerException("The email:" + email + " has been registered");
- // }
- BaseLock usernameLock = getLock(entity, username, null);
- if (usernameLock != null && !usernameLock.getLock()) {
- alertNameTaken(entity, username);
- }
- BaseLock emailLock = null;
- if (!username.toLowerCase().equals(email.toLowerCase())) {
- emailLock = getLock(entity, email, null);
- }
- if (emailLock != null && !emailLock.getLock()) {
- alertNameTaken(entity, email);
- }
- try {
- User user = new User();
- //密码加密
- userRegist.setPassword(BCrypt.hashpw(userRegist.getPassword(), BCrypt.gensalt()));
- BeanUtils.copyProperties(userRegist, user);
- //添加用户
- if (userMapper.insert(user) <= 0) {
- log.info("Regist fail, userRegist:{}", userRegist.toString());
- throw new ServerException("Regist fail, unspecified error");
- }
- //添加成功,发送激活邮件
- // sendMail(user.getEmail(), user);
- return user;
- } finally {
- releaseLock(usernameLock);
- releaseLock(emailLock);
- }
- }
- @Override
- public User externalRegist(OAuth2AuthenticationToken oauthAuthToken) throws ServerException {
- OAuth2User oauthUser = oauthAuthToken.getPrincipal();
- User user = getByUsername(oauthUser.getName());
- if (user != null) {
- return user;
- }
- user = new User();
- String emailMapping = environment.getProperty(String.format("spring.security.oauth2.client.provider.%s.userMapping.email", oauthAuthToken.getAuthorizedClientRegistrationId()));
- String nameMapping = environment.getProperty(String.format("spring.security.oauth2.client.provider.%s.userMapping.name", oauthAuthToken.getAuthorizedClientRegistrationId()));
- String avatarMapping = environment.getProperty(String.format("spring.security.oauth2.client.provider.%s.userMapping.avatar", oauthAuthToken.getAuthorizedClientRegistrationId()));
- JSONObject jsonObj = new JSONObject(oauthUser.getAttributes());
- user.setName(JsonPath.read(jsonObj, nameMapping));
- user.setUsername(oauthUser.getName());
- user.setPassword("OAuth2");
- user.setEmail(JsonPath.read(jsonObj, emailMapping));
- user.setAvatar(JsonPath.read(jsonObj, avatarMapping));
- int insert = userMapper.insert(user);
- if (insert > 0) {
- return user;
- } else {
- log.info("Regist fail, username:{}", oauthUser.getName());
- throw new ServerException("Regist fail, unspecified error");
- }
- }
- protected void alertNameTaken(CheckEntityEnum entity, String name) throws ServerException {
- log.warn("The {} username or email {} has been registered", entity.getSource(), name);
- throw new ServerException("The " + entity.getSource() + " username or email has been registered");
- }
- /**
- * 根据用户名获取用户
- *
- * @param username
- * @return
- */
- @Override
- public User getByUsername(String username) {
- return userMapper.selectByUsername(username);
- }
- /**
- * 用户登录
- *
- * @param userLogin
- * @return
- */
- @Override
- public User userLogin(UserLogin userLogin) throws ServerException {
- String username = userLogin.getUsername();
- String password = userLogin.getPassword();
- User user = getByUsername(username);
- if (user != null) {
- // 校验密码
- boolean checkpw = false;
- try {
- checkpw = BCrypt.checkpw(password, user.getPassword());
- } catch (Exception e) {
- }
- if (checkpw) {
- return user;
- }
- if (ldapLogin(username, password)) {
- return user;
- }
- log.info("Username({}) password is wrong", username);
- throw new ServerException("Username or password is wrong");
- }
- user = ldapAutoRegist(username, password);
- if (user == null) {
- throw new ServerException("Username or password is wrong");
- }
- return user;
- }
- private boolean ldapLogin(String username, String password) {
- if (!ldapService.existLdapServer()) {
- return false;
- }
- LdapPerson ldapPerson = ldapService.findByUsername(username, password);
- if (null == ldapPerson) {
- return false;
- }
- return true;
- }
- private User ldapAutoRegist(String username, String password) {
- if (!ldapService.existLdapServer()) {
- return null;
- }
- LdapPerson ldapPerson = ldapService.findByUsername(username, password);
- if (null == ldapPerson) {
- throw new ServerException("Username or password is wrong");
- }
- String email = ldapPerson.getEmail();
- if (userMapper.existEmail(ldapPerson.getEmail())) {
- log.info("Ldap auto regist fail, the email {} has been registered", email);
- throw new ServerException("Ldap auto regist fail: the email " + email + " has been registered");
- }
- if (userMapper.existUsername(ldapPerson.getSAMAccountName())) {
- ldapPerson.setSAMAccountName(email);
- }
- return ldapService.registPerson(ldapPerson);
- }
- /**
- * 查询用户
- *
- * @param keyword
- * @param user
- * @param orgId
- * @param includeSelf
- * @return
- */
- @Override
- public List<UserBaseInfo> getUsersByKeyword(String keyword, User user, Long orgId, Boolean includeSelf) {
- List<UserBaseInfo> users = userMapper.getUsersByKeyword(keyword, orgId);
- if (includeSelf) {
- return users;
- }
- Iterator<UserBaseInfo> iterator = users.iterator();
- while (iterator.hasNext()) {
- UserBaseInfo userBaseInfo = iterator.next();
- if (userBaseInfo.getId().equals(user.getId())) {
- iterator.remove();
- }
- }
- return users;
- }
- /**
- * 更新用户
- *
- * @param user
- * @return
- */
- @Override
- @Transactional
- public boolean updateUser(User user) throws ServerException {
- if (userMapper.updateBaseInfo(user) <= 0) {
- log.info("Update user fail, username:{}", user.getUsername());
- throw new ServerException("Update user fail");
- }
- return true;
- }
- @Override
- @Transactional
- public ResultMap activateUserNoLogin(String token, HttpServletRequest request) {
- ResultMap resultMap = new ResultMap(tokenUtils);
- token = AESUtils.decrypt(token, null);
- String username = tokenUtils.getUsername(token);
- if (null == username) {
- return resultMap.fail().message("The activate toke is invalid");
- }
- User user = getByUsername(username);
- if (null == user) {
- return resultMap.fail().message("The activate toke is invalid");
- }
- // 已经激活,不需要再次激活
- if (user.getActive()) {
- return resultMap.fail().message("The current user is activated and doesn't need to be reactivated");
- }
- BaseLock lock = LockFactory.getLock("ACTIVATE" + Consts.AT_SYMBOL + username.toUpperCase(), 5, LockType.REDIS);
- if (lock != null && !lock.getLock()) {
- return resultMap.fail().message("The current user is activating");
- }
- try {
- // 验证激活token
- if (tokenUtils.validateToken(token, user)) {
- user.setActive(true);
- user.setUpdateTime(new Date());
- userMapper.activeUser(user);
- String orgName = user.getUsername() + "'s Organization";
- // 激活成功,创建默认Organization
- Organization organization = new Organization(orgName, null, user.getId());
- organizationMapper.insert(organization);
- // 关联用户和组织,创建人是组织的owner
- RelUserOrganization relUserOrganization = new RelUserOrganization(organization.getId(), user.getId(),
- UserOrgRoleEnum.OWNER.getRole());
- relUserOrganization.createdBy(user.getId());
- relUserOrganizationMapper.insert(relUserOrganization);
- UserLoginResult userLoginResult = new UserLoginResult();
- BeanUtils.copyProperties(user, userLoginResult);
- return resultMap.success(tokenUtils.generateToken(user)).payload(userLoginResult);
- }
- return resultMap.fail().message("The activate toke is invalid");
- } finally {
- releaseLock(lock);
- }
- }
- /**
- * 发送邮件
- *
- * @param email
- * @param user
- * @return
- */
- @Override
- public boolean sendMail(String email, User user) throws ServerException {
- //校验邮箱
- if (!email.equals(user.getEmail())) {
- throw new ServerException("The current email address is not match user email address");
- }
- Map<String, Object> content = new HashMap<String, Object>();
- content.put("username", user.getUsername());
- content.put("host", serverUtils.getHost());
- content.put("token", AESUtils.encrypt(tokenUtils.generateContinuousToken(user), null));
- MailContent mailContent = MailContent.MailContentBuilder.builder()
- .withSubject(Constants.USER_ACTIVATE_EMAIL_SUBJECT)
- .withTo(user.getEmail())
- .withMainContent(MailContentTypeEnum.TEMPLATE)
- .withTemplate(Constants.USER_ACTIVATE_EMAIL_TEMPLATE)
- .withTemplateContent(content)
- .build();
- mailUtils.sendMail(mailContent, null);
- return true;
- }
- /**
- * 修改用户密码
- *
- * @param user
- * @param oldPassword
- * @param password
- * @param request
- * @return
- */
- @Override
- @Transactional
- public ResultMap changeUserPassword(User user, String oldPassword, String password, HttpServletRequest request) {
- ResultMap resultMap = new ResultMap(tokenUtils);
- //校验原密码
- if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
- return resultMap.failAndRefreshToken(request).message("Incorrect original password");
- }
- //设置新密码
- user.setPassword(BCrypt.hashpw(password, BCrypt.gensalt()));
- user.setUpdateTime(new Date());
- if (userMapper.changePassword(user) > 0) {
- return resultMap.success().message("Successful password modification");
- }
- return resultMap.failAndRefreshToken(request);
- }
- /**
- * 上传头像
- *
- * @param user
- * @param file
- * @param request
- * @return
- */
- @Override
- @Transactional
- public ResultMap uploadAvatar(User user, MultipartFile file, HttpServletRequest request) {
- ResultMap resultMap = new ResultMap(tokenUtils);
- //校验文件是否图片
- if (!fileUtils.isImage(file)) {
- return resultMap.failAndRefreshToken(request).message("File format error");
- }
- //上传文件
- String fileName = user.getUsername() + "_" + UUID.randomUUID();
- String avatar = null;
- try {
- avatar = fileUtils.upload(file, Constants.USER_AVATAR_PATH, fileName);
- if (StringUtils.isEmpty(avatar)) {
- return resultMap.failAndRefreshToken(request).message("User avatar upload error");
- }
- } catch (Exception e) {
- log.error("User avatar upload error, username:{}", user.getUsername(), e);
- return resultMap.failAndRefreshToken(request).message("User avatar upload error");
- }
- //删除原头像
- if (!StringUtils.isEmpty(user.getAvatar())) {
- fileUtils.remove(user.getAvatar());
- }
- //修改用户头像
- user.setAvatar(avatar);
- user.setUpdateTime(new Date());
- if (userMapper.updateAvatar(user) > 0) {
- Map<String, String> map = new HashMap<>();
- map.put("avatar", avatar);
- return resultMap.successAndRefreshToken(request).payload(map);
- }
- return resultMap.failAndRefreshToken(request).message("Server error, user avatar update fail");
- }
- /**
- * 查询用户信息
- *
- * @param id
- * @param user
- * @param request
- * @return
- */
- @Override
- public ResultMap getUserProfile(Long id, User user, HttpServletRequest request) {
- ResultMap resultMap = new ResultMap(tokenUtils);
- User tempUser = userMapper.getById(id);
- if (null == tempUser) {
- return resultMap.failAndRefreshToken(request).message("User not found");
- }
- UserProfile userProfile = new UserProfile();
- BeanUtils.copyProperties(tempUser, userProfile);
- if (id.equals(user.getId())) {
- List<OrganizationInfo> organizationInfos = organizationMapper.getOrganizationByUser(user.getId());
- userProfile.setOrganizations(organizationInfos);
- return resultMap.successAndRefreshToken(request).payload(userProfile);
- }
- Long[] userIds = {user.getId(), id};
- List<OrganizationInfo> jointlyOrganization = organizationMapper.getJointlyOrganization(Arrays.asList(userIds), id);
- if (!CollectionUtils.isEmpty(jointlyOrganization)) {
- BeanUtils.copyProperties(tempUser, userProfile);
- userProfile.setOrganizations(jointlyOrganization);
- return resultMap.successAndRefreshToken(request).payload(userProfile);
- }
- return resultMap.failAndRefreshToken(request, HttpCodeEnum.UNAUTHORIZED).message("You have not permission to view the user's information because you don't have any organizations that join together");
- }
- @Override
- public ResultMap getUserProfileFromToken(String token) {
- String username = tokenUtils.getUsername(Constants.TOKEN_PREFIX + Constants.SPACE + token);
- User user = getByUsername(username);
- if (null == user) {
- return new ResultMap().fail(HttpCodeEnum.FORBIDDEN.getCode()).message(ErrorMsg.ERR_MSG_PERMISSION);
- }
- if (!tokenUtils.validateToken(token, user)) {
- return new ResultMap().fail(HttpCodeEnum.FORBIDDEN.getCode()).message(ErrorMsg.ERR_MSG_PERMISSION);
- }
- UserProfile userProfile = new UserProfile();
- BeanUtils.copyProperties(user, userProfile);
- List<OrganizationInfo> organizationInfos = organizationMapper.getOrganizationByUser(user.getId());
- userProfile.setOrganizations(organizationInfos);
- return new ResultMap().success(tokenUtils.generateToken(user)).payload(userProfile);
- }
- @Override
- public String forgetPassword(UserDistinctType userDistinctType, UserDistinctTicket ticket) {
- User user = null;
- switch (userDistinctType) {
- case EMAIL:
- String email = ticket.getTicket();
- if (StringUtils.isEmpty(email)) {
- throw new ServerException("Email cannot be empty!");
- }
- Matcher matcher = Constants.PATTERN_EMAIL_FORMAT.matcher(email);
- if (!matcher.find()) {
- throw new ServerException("Invalid email format!");
- }
- user = userMapper.selectByUsername(email);
- if (user == null) {
- throw new ServerException("The current email is not registered in Davinci");
- }
- break;
- case USERNAME:
- String username = ticket.getTicket();
- if (StringUtils.isEmpty(username)) {
- throw new ServerException("Username cannot be EMPTY!");
- }
- user = userMapper.selectByUsername(username);
- if (user == null) {
- throw new ServerException("The current username is not registered in Davinci");
- }
- break;
- default:
- throw new NotFoundException("Unknown request uri");
- }
- String checkCode = TokenUtils.randomPassword();
- user.setPassword(checkCode);
- String checkToken = tokenUtils.generateToken(user, TOKEN_TIMEOUT_MILLIS);
- Map<String, Object> content = new HashMap<>(3);
- content.put("ticket", ticket.getTicket());
- content.put("checkCode", checkCode);
- MailContent mailContent = MailContent.MailContentBuilder.builder()
- .withSubject(Constants.USER_REST_PASSWORD_EMAIL_SUBJECT)
- .withTo(user.getEmail())
- .withMainContent(MailContentTypeEnum.TEMPLATE)
- .withTemplate(Constants.USER_REST_PASSWORD_EMAIL_TEMPLATE)
- .withTemplateContent(content)
- .build();
- mailUtils.sendMail(mailContent, null);
- return StringZipUtil.compress(checkToken);
- }
- @Override
- @Transactional
- public boolean resetPassword(UserDistinctType userDistinctType, String token, UserDistinctTicket ticket) {
- User user = null;
- switch (userDistinctType) {
- case EMAIL:
- String email = ticket.getTicket();
- if (StringUtils.isEmpty(email)) {
- throw new ServerException("Email cannot be EMPTY!");
- }
- Matcher matcher = Constants.PATTERN_EMAIL_FORMAT.matcher(email);
- if (!matcher.find()) {
- throw new ServerException("Invalid email format!");
- }
- user = userMapper.selectByUsername(email);
- if (user == null) {
- throw new ServerException("The current email is not registered in Davinci");
- }
- break;
- case USERNAME:
- String username = ticket.getTicket();
- if (StringUtils.isEmpty(username)) {
- throw new ServerException("Username cannot be EMPTY!");
- }
- user = userMapper.selectByUsername(username);
- if (user == null) {
- throw new ServerException("The current username is not registered in Davinci");
- }
- break;
- default:
- throw new NotFoundException("Unknown request uri");
- }
- if (StringUtils.isEmpty(ticket.getCheckCode())) {
- throw new ServerException("Check code cannot be Empty");
- }
- if (StringUtils.isEmpty(ticket.getPassword())) {
- throw new ServerException("Password cannot be Empty");
- }
- String decompress = StringZipUtil.decompress(token);
- user.setPassword(ticket.getCheckCode());
- if (!tokenUtils.validateToken(decompress, user)) {
- throw new ServerException("Invalid check code, check code is wrong or has expired");
- }
- user.setPassword(BCrypt.hashpw(ticket.getPassword(), BCrypt.gensalt()));
- return userMapper.changePassword(user) > 0;
- }
- }
|