美文网首页
java web 邮箱找回密码

java web 邮箱找回密码

作者: wanggs | 来源:发表于2018-10-27 14:17 被阅读0次

邮箱激活

背景:几乎每个网站或论坛之类的用户注册后都需要通过发送邮件到邮箱激活用户。
设计:
激活步骤:
  1. 发送激活邮件

  2. 用户查收邮件

  3. 用户点击链接,跳转至成功页面(修改激活状态),激活成功。

  4. 加密能防止伪造攻击,一次url只能验证一次,并且绑定了用户。生成url: 可以用UUID生成随机密钥。

数字签名 = MD5(用户名+'′+过期时间+‘’+密钥key)
数据库字段(用户名(主键),密钥key,过期时间)
url参数(用户名,数字签名) ,密钥key的生成:在每一个用户找回密码时候为这个用户生成一个密钥key ,

详细步骤

点击找回密码按钮 > 跳到找回密码页面 > 输入手机号或者邮箱找回 > 后台验证根据邮箱或者密码是否能在数据库中找到对应的user(信息),如果找不到,证明手机号或者邮箱伪造的,如果找得到 > 把生成的uuid 作为token(证明本次用户的唯一标示)当成键user做为值放入缓存中,然后拼接链接,同时放入要发送的邮箱中, http://localhost:8080/foundpassword?token=f3a29a4b795a4f77be98ea931cf9884d 发送邮箱 > 当用户点击邮箱链接的时候,后台获取token, 首先判断token 是否为空,如果存在去缓存中获取对应的user 防止伪造token,
如果都没有问题,请求转发到重置密码页面把token放到表单隐藏域中,当用户提交表单的时候,对比两次密码是否一致,然后再次验证toke是否伪造,如果都是ok的话,根据token值删除缓存,同时更新用户密码,然后重定向到登陆页面.

代码

package com.kaishengit.service.impl;


/**
 * Created by wanggs on 2017/9/26.
 */
@Service
public class UserServiceImpl implements UserService {
    private static Logger logger = (Logger) LoggerFactory.getLogger(UserService.class);
    @Autowired
    private SimpleCache simpleCache;
    // 从配置文件中获取盐值
    @Value("${user.password.salt}")
    private String salt;
    @Value("${email.smpt}")
    protected String smpt;
    @Value("${email.port}")
    public String port;
    @Value("${email.username}")
    private String username;
    @Value("${email.password}")
    private String password;
    @Value("${email.frommail}")
    private String formmail;
    @Autowired
    private UserMapper userMapper;

    // 发送激活用户账号的邮件,写进去时间,如果没人访问就过期,有人访问就延期时间
    private static Cache<String, String> cache = CacheBuilder
            .newBuilder()
            .expireAfterWrite(6, TimeUnit.HOURS)
            .build();
    // 找回密码token
    private static Cache<String, String> passwordCache = CacheBuilder.newBuilder()
            .expireAfterWrite(30, TimeUnit.MINUTES)
            .build();
    // 限制操作pinlv
    private static Cache<String, String> activeCache = CacheBuilder.newBuilder()
            .expireAfterWrite(30, TimeUnit.SECONDS)
            .build();

    @Override
    public User findByName(String username) {
        return userMapper.findByUsername(username);
    }

    @Override
    public User findByEmail(String email) {
        return userMapper.finByEmail(email);
    }

    /**
     * 注册用户
     *
     * @param user
     * @throws UserExistException
     */
    @Override
    public void saveNewUser(User user) throws UserExistException {
        User u = userMapper.findByUsername(user.getUsername());
        if (u != null) {
            throw new UserExistException("用户名已经存在");
        }
        user.setPassword(DigestUtils.md5Hex(user.getPassword() + salt));
        user.setState(User.USERSTATE_UNACTIVE);
        user.setAvatar(User.DEFAULT_AVATAR_NAME);
        logger.info("盐值:{}" + salt);
        logger.info("加密后密码是: {}", user.getPassword());

        userMapper.saveNewUser(user);
        // 创建线程发激活邮件
        getThread(user);
    }

    /**
     * 使用线程发送激活邮件
     *
     * @param user
     */
    private void getThread(User user) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 发送激活邮件
                String uuid = UUID.randomUUID().toString().replace("-", "");
                String url = "http://localhost/user/active?_=" + uuid;
                // 放入缓存等待6小时
                cache.put(uuid, user.getUsername());
                String html = "<h3>Dear " + user.getUsername() + ":</h3>请点击<a href='" + url + "'>该链接</a>去激活你的账号. <br> 凯盛软件";
                Email email = getEmail(smpt, port, username, password, formmail);
                logger.info("邮箱:{}" + email);
                EmailUtil.sendHtmlEmail(email, user.getEmail(), "用户激活邮件", html);
            }
        });

        thread.start();
    }

    /**
     * 验证token
     *
     * @param token
     */
    @Override
    public void activeUser(String token) throws ServiceException {
        String userName = cache.getIfPresent(token);
        logger.info("token: {}" + token);
        if (token == null) {
            throw new ServiceException("token无效或者过期");
        } else {
            User user = userMapper.findByUsername(userName);
            if (user == null) {
                throw new ServiceException("账号不存在");
            } else {
                // 设置激活
                user.setState(Statu.Active.getValue());
                // 更新用户
                userMapper.update(user);

                // 删除缓存中的键对应的值
                cache.invalidate(token);
            }
        }
    }

    /**
     * 用户找回密码
     *
     * @param sessionId 客户端的sessionID,限制客户端的操作频率
     * @param type      找回密码方式 email | phone
     * @param value     电子邮件地址 | 手机号码
     */
    @Override
    public void funndpassword(String sessionId, String type, String value) {

        if (activeCache.getIfPresent(sessionId) == null) {
            if ("phone".equals(type)) {
                // TODO 根据手机号找
            }
            if ("email".equals(type)) {
                // 根据邮箱找
                User user = userMapper.finByEmail(value);
                if (user != null) {
                    // 开启线程发邮件
                    getThread(value, user);
                }

            }
            activeCache.put(sessionId, "xxxx");
        } else {
            throw new ServiceException("操作频率过快,稍后再试");
        }
    }

    /**
     * 使用线程发送找回密码
     *
     * @param value
     * @param user
     */
    private void getThread(String value, User user) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                String uuid = UUID.randomUUID().toString().replace("-", "");
                passwordCache.put(uuid, user.getUsername());
                String url = "http://localhost/foundpassword/newpassword?token=" + uuid;
                String html = user.getUsername() + "<<br>请点击该<a href='" + url + "'>链接</a>进行找回密码操作,链接在30分钟内有效";
                Email email = getEmail(smpt, port, username, password, formmail);
                logger.info("邮箱:{}" + email);
                EmailUtil.sendHtmlEmail(email, value, "密码找回邮件", html);
            }
        });
        thread.start();
    }

    @Override
    public void update(User user) {
        userMapper.update(user);
    }

    /**
     * 找回密码
     *
     * @param token
     * @return
     */
    @Override
    public User foundPasswordGetUserByToken(String token) throws ServiceException {
        String username = passwordCache.getIfPresent(token);
        if (StringUtils.isBlank(username)) {
            throw new ServiceException("token过期或错误");
        } else {
            User user = userMapper.findByUsername(username);
            if (user == null) {
                throw new ServiceException("未找到对应账号");
            } else {
                return user;
            }
        }
    }

    /**
     * 重置密码
     *
     * @param user
     * @param toke
     */
    @Override
    public void resetPassword(User user, String toke) {
        String username = passwordCache.getIfPresent(toke);
        if (StringUtils.isBlank(toke) && StringUtils.isBlank(username)) {
            throw new ServiceException("token过期,或者错误");
        } else {
            User u = userMapper.findByUsername(username);
            if (u != null) {
                u.setPassword(DigestUtils.md5Hex(user.getPassword() + salt));
                userMapper.update(u);

                // 删除token
                passwordCache.invalidate(toke);
                logger.info("{} 重置了密码", u.getUsername());
            }
        }
    }

    /**
     * 更改邮箱
     *
     * @param user
     */
    @Override
    public void updateEmail(User user, FormParam param) {
        if (StringUtils.isBlank(user.getUsername()) && StringUtils.isBlank(user.getEmail())) {
            throw new ServiceException("帐号或者密码不能为空");
        }
        user.setEmail(param.getEmail());
        userMapper.update(user);
    }

    /**
     * 修改密码
     *
     * @param param
     */
    @Override
    public void updatePassword(User user, FormParam param) {
        if (param == null) {
            throw new ServiceException("参数不能为空");
        }
        String oldpassword = DigestUtils.md5Hex(param.getOldpassword() + salt);
        System.out.println("原始密码:" + oldpassword);
        System.out.println("密码:" + user.getPassword());
        if (!user.getPassword().equals(oldpassword)) {
            throw new ServiceException("原始密码错误");
        }
        // 密码加密
        user.setPassword(DigestUtils.md5Hex(param.getNewpassword() + salt));
        userMapper.update(user);

    }

    @Override
    public void updateAvatar(User user, FormParam param) {
        if (StringUtils.isBlank(param.getFileKey())) {
            throw new ServiceException("七牛云参数为空");
        }
        user.setAvatar(param.getFileKey());
        userMapper.update(user);
    }

    @Override
    public AjaxResult getAjaxResult(FormParam param, String action, User user, String password) {
        if ("avatar".equals(action)) {
            try {
                this.updateAvatar(user, param);
                return new AjaxResult(AjaxResult.SUCCESS);
            } catch (ServiceException e) {
                return new AjaxResult(AjaxResult.ERROR, e.getMessage());
            }
        }
        if ("profile".equals(action)) {
            try {
                this.updateEmail(user, param);
                return new AjaxResult(AjaxResult.SUCCESS);
            } catch (ServiceException e) {
                return new AjaxResult(AjaxResult.ERROR, e.getMessage());
            }
        }
        if ("password".equals(action)) {
            try {
                this.updatePassword(user, param);
                return new AjaxResult(AjaxResult.SUCCESS);
            } catch (ServiceException e) {
                return new AjaxResult(AjaxResult.ERROR, e.getMessage());
            }

        }
        return new AjaxResult(AjaxResult.ERROR, "参数有误");
    }


    /**
     * 根据id查找对象
     *
     * @param userid
     * @return
     */
   private  static Map<String,Object> map = Maps.newHashMap();
    @Override
    public User findById(Integer userid) {


        User user = (User)map.get("user:" + userid);
        if (user == null) {
            user = userMapper.findById(userid);
            map.put("user:" + userid, user);
        }else {
            logger.debug("load user from cache");
        }

        return user;
    }


    /**
     * 封装Email对象
     *
     * @param smpt
     * @param port
     * @param username
     * @param password
     * @param formmail
     * @return
     */
    private Email getEmail(String smpt, String port, String username, String password, String formmail) {
        return new Email(smpt, port, username, password, formmail);
    }
}

相关文章

  • java web 邮箱找回密码

    邮箱激活 背景:几乎每个网站或论坛之类的用户注册后都需要通过发送邮件到邮箱激活用户。 设计: 激活步骤: 发送激活...

  • 如何通过JAVA发送邮件

    一般用户注册、找回密码,都是通过 手机 和 邮箱 找回密码的!我这通过示范126邮箱发送编写发送邮件服务! 导入J...

  • 小恩爱找回密码流程

    一、找回密码流程 二、分析 优点:对于密码找回,小恩爱其实已经做了改进,从之前的自己选择类型(手机、邮箱、恩爱号)...

  • 常见的操作问题?

    忘记登录密码,可通过邮箱找回,在登录页面下面点击密码重置…… 自己的帐户及邮箱一定要牢记… 为了个人帐户安全,半年...

  • 邮件发送

    应用场景:系统找回密码,严重码发送邮箱,或者预警信息发送通知者邮箱,并做日志记录 公共类:EmailHelper ...

  • EduSoho 常见问题解决[0002] 忘记管理密码找回密码

    1、找回密码接口输入管理账号手机或邮箱,需开启手机或邮箱功能。 2、通过PHPmyadmin软件重置数据库。如果没...

  • .net邮件发送

    1、web.config文件配置,发送方邮箱账号、密码、邮箱类型 2、新建email文件 3、在email文件中填...

  • IDCM 忘记密码怎么办

    1、如您忘记密码,在IDCM登陆页面,请点击: 2、您可以使用手机或邮箱验证码找回密码。以手机验证码找回为例,输入...

  • Web实战之密码找回

    密码找回是几乎所有Web应用都需要的,一般均通过邮件的方式,这里我先实现一种最简单的密码找回——将密码重置为随机字...

  • 2022-09-21又弄丢了

    我去登录CSDN,邮箱号密码错误、手机号码不存在;我去试着找回密码,显示邮箱不存在、手机号不存在……我才想起来,原...

网友评论

      本文标题:java web 邮箱找回密码

      本文链接:https://www.haomeiwen.com/subject/yskdtqtx.html