com.github.dactiv.fear.user.service.account.AccountService.java Source code

Java tutorial

Introduction

Here is the source code for com.github.dactiv.fear.user.service.account.AccountService.java

Source

/*
 * Copyright 2015 dactiv
 *
 * 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 com.github.dactiv.fear.user.service.account;

import com.github.dactiv.fear.commons.Apis;
import com.github.dactiv.fear.commons.Casts;
import com.github.dactiv.fear.commons.entity.Mail;
import com.github.dactiv.fear.commons.exception.ServiceException;
import com.github.dactiv.fear.commons.service.auth.Subjects;
import com.github.dactiv.fear.user.service.TokenExpiredException;
import com.github.dactiv.fear.user.service.TokenNotFoundException;
import com.github.dactiv.fear.user.service.ValidToken;
import com.github.dactiv.universe.captcha.entity.ValidResult;
import com.github.dactiv.universe.captcha.support.HttpSessionCaptchaManager;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * ?
 *
 * @author maurice
 */
@Service
public class AccountService {

    // ????
    private final static String DEFAULT_VALID_MAIL_CACHE_NAME = "validMailCache";
    // ????
    private final static String DEFAULT_FORGOT_PASSWORD_CACHE_NAME = "forgotPasswordCache";
    // ?????
    private final static String DEFAULT_RESET_PASSWORD_CACHE_NAME = "resetPasswordCache";
    // ?
    private final long DEFAULT_VALID_MAIL_EXPIRED_TIME = 86400000L;
    // ??
    private final long DEFAULT_FORGOT_PASSWORD_EXPIRED_TIME = 1800000L;
    // ???
    private final long DEFAULT_RESET_PASSWORD_EXPIRED_TIME = 600000L;

    @Autowired
    private Configuration freemarkerConfiguration;

    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private HttpSessionCaptchaManager captchaManager;

    // ???
    private String validMailCacheName = DEFAULT_VALID_MAIL_CACHE_NAME;
    // ????
    private String forgotPasswordCacheName = DEFAULT_FORGOT_PASSWORD_CACHE_NAME;
    // ?????
    private String resetPasswordCacheName = DEFAULT_RESET_PASSWORD_CACHE_NAME;
    // ?
    private long validMailExpiredTime = DEFAULT_VALID_MAIL_EXPIRED_TIME;
    // ??
    private long forgotPasswordExpiredTime = DEFAULT_FORGOT_PASSWORD_EXPIRED_TIME;
    // ???
    private long resetPasswordExpiredTime = DEFAULT_RESET_PASSWORD_EXPIRED_TIME;

    /**
     * ???
     *
     * @param validMailCacheName ??
     */
    public void setValidMailCacheName(String validMailCacheName) {
        this.validMailCacheName = validMailCacheName;
    }

    /**
     * ????
     *
     * @param forgotPasswordCacheName ????
     */
    public void setForgotPasswordCacheName(String forgotPasswordCacheName) {
        this.forgotPasswordCacheName = forgotPasswordCacheName;
    }

    /**
     * ?????
     *
     * @param resetPasswordCacheName ?????
     */
    public void setResetPasswordCacheName(String resetPasswordCacheName) {
        this.resetPasswordCacheName = resetPasswordCacheName;
    }

    /**
     * ?
     *
     * @param validMailExpiredTime 
     */
    public void setValidMailExpiredTime(long validMailExpiredTime) {
        this.validMailExpiredTime = validMailExpiredTime;
    }

    /**
     * ??
     *
     * @param forgotPasswordExpiredTime ??
     */
    public void setForgotPasswordExpiredTime(long forgotPasswordExpiredTime) {
        this.forgotPasswordExpiredTime = forgotPasswordExpiredTime;
    }

    /**
     * ???
     *
     * @param resetPasswordExpiredTime ???
     */
    public void setResetPasswordExpiredTime(long resetPasswordExpiredTime) {
        this.resetPasswordExpiredTime = resetPasswordExpiredTime;
    }

    /**
     * 
     *
     * @param entity  map
     * @return 
     * @throws Exception
     */
    public Map<String, Object> registration(Map<String, Object> entity) throws Exception {

        entity.put("state", 1);
        entity.put("nickname", entity.get("username"));
        entity.put("isAdmin", 0);

        Apis.invoke("accountService", "registration", entity);

        return entity;
    }

    /**
     * ???
     *
     * @param mail ???
     * @throws Exception
     */
    public void sendValidMail(String mail) throws Exception {

        Boolean flag = Apis.invoke("accountService", "isUsernameUnique", mail);

        if (!flag) {
            throw new ServiceException("" + mail + "");
        }

        Map<String, Object> principal = Subjects.getPrincipal();
        String id = new Md5Hash(mail + principal.get("id") + System.currentTimeMillis()).toHex();

        ValidToken entity = new MailValidToken(id, new Date(), mail, principal);
        Cache cache = cacheManager.getCache(validMailCacheName);

        cache.put(id, entity);

        Template template = freemarkerConfiguration.getTemplate("registration.ftl", "UTF-8");
        String message = FreeMarkerTemplateUtils.processTemplateIntoString(template, entity);

        Mail mailEntity = new Mail(mail, "?", message, Boolean.TRUE);
        Apis.invoke("messageService", "sendMail", mailEntity);
    }

    /**
     * ?
     *
     * @param id  id
     *
     */
    public void validMail(String id) {

        Cache cache = cacheManager.getCache(validMailCacheName);
        MailValidToken entity = cache.get(id, MailValidToken.class);

        if (entity == null) {
            throw new TokenNotFoundException("?ID[" + id + "]?");
        }

        try {
            long creationTime = entity.getCreationDate().getTime();
            long currentTime = System.currentTimeMillis();

            if (currentTime - creationTime > validMailExpiredTime) {
                cache.evict(id);
                throw new TokenExpiredException("ID[" + entity.getId() + "]");
            }

            Map<String, Object> principal = Subjects.getPrincipal();

            if (!principal.get("id").equals(entity.getPrincipal().get("id"))) {
                throw new ServiceException("???");
            }

            principal.put("isBindingMail", 1);
            principal.put("email", entity.getMail());

            Apis.invoke("accountService", "saveUser", principal, new ArrayList<>());
        } finally {
            cache.evict(id);
        }
    }

    /**
     * ?
     *
     * @param username ??
     * @param captcha ??
     */
    public Map<String, Object> forgotPassword(String username, String captcha) throws Exception {

        HttpSession session = (HttpSession) RequestContextHolder.currentRequestAttributes().getSessionMutex();
        captchaManager.setCurrentSession(session);

        ValidResult validResult = captchaManager.valid(session.getId(), captcha);

        if (validResult.getIsValid()) {
            throw new ServiceException(validResult.getMessage());
        }

        Map<String, Object> user = Apis.invoke("accountService", "getUserByUsernameOrEmail", username);

        if (MapUtils.isEmpty(user)) {
            throw new ServiceException("?[" + username + "]");
        }

        sendForgetPasswordMail(user);

        return user;
    }

    /**
     * ???
     *
     * @param user ?
     * @throws Exception
     */
    private void sendForgetPasswordMail(Map<String, Object> user) throws Exception {
        String email = Casts.cast(user.get("email"), String.class);

        if (StringUtils.isEmpty(email)) {
            throw new ServiceException("?[" + user.get("username") + "]?");
        }

        String id = new Md5Hash(email + user.get("id") + System.currentTimeMillis()).toHex();

        ValidToken entity = new ValidToken(id, new Date(), user);
        Cache cache = cacheManager.getCache(forgotPasswordCacheName);

        cache.put(id, entity);

        Map<String, Object> data = new HashMap<>();

        data.put("user", user);
        data.put("vme", entity);

        Template template = freemarkerConfiguration.getTemplate("forgot-password.ftl", "UTF-8");
        String message = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);

        Mail mailEntity = new Mail(email, "??", message, Boolean.TRUE);
        Apis.invoke("messageService", "sendMail", mailEntity);

    }

    /**
     * ?? key
     *
     * @param id key
     *
     * @return ??? map?
     */
    public ValidToken validForgotPassword(String id) {

        Cache cache = cacheManager.getCache(forgotPasswordCacheName);
        ValidToken entity = cache.get(id, ValidToken.class);
        if (entity == null) {
            throw new TokenNotFoundException("???");
        }

        try {

            long creationTime = entity.getCreationDate().getTime();
            long currentTime = System.currentTimeMillis();

            if (currentTime - creationTime > forgotPasswordExpiredTime) {
                throw new TokenExpiredException("ID[" + entity.getId() + "]");
            }
        } finally {
            cache.evict(id);
        }

        Map<String, Object> principal = entity.getPrincipal();
        id = new Md5Hash(principal.get("id").toString() + System.currentTimeMillis()).toHex();
        ValidToken validToken = new ValidToken(id, new Date(), principal);

        cache = cacheManager.getCache(resetPasswordCacheName);
        cache.put(id, validToken);

        return validToken;
    }

    /**
     * ??
     *
     * @param id       token id
     * @param password ?
     */
    public void resetPassword(String id, String password, String confirmPassword) {

        if (!StringUtils.equals(password, confirmPassword)) {
            throw new ServiceException("????");
        }

        Cache cache = cacheManager.getCache(resetPasswordCacheName);
        ValidToken entity = cache.get(id, ValidToken.class);

        if (entity == null) {
            throw new TokenNotFoundException("???");
        }

        long creationTime = entity.getCreationDate().getTime();
        long currentTime = System.currentTimeMillis();

        try {
            if (currentTime - creationTime > resetPasswordExpiredTime) {
                throw new TokenExpiredException("ID[" + entity.getId() + "]");
            }

            Integer userId = Casts.cast(entity.getPrincipal().get("id"), Integer.class);

            Apis.invoke("accountService", "updateUserPassword", userId, password);
        } finally {
            cache.evict(id);
        }
    }
}