English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

SpringMVCでメールを通じてパスワードをリセットする機能の実現

最近、システムを開発していて、忘れられたパスワードをメールで再設定する必要があるという要件がありました。現在のシステムでは、登録時にメールを強制的に入力させることで、メールをバインドしてパスワードを再設定できるようにしています。Javaでメールを送信する機能については言及しませんが、パスワードの再設定に焦点を当てます。

他者のアイデアを参考に:メールを送信→メール内のURLをリクエスト→URLを確認→{確認成功でパスワードを変更、確認失敗で失敗ページに遷移}

重要なのは、このurlをどのように生成し、どのように解析するかです。
注意すべきことは、一度のurlは一度だけパスワードを変更できることです、同じアカウントが複数のメールを送信した場合、最後のメールのurlのみが有効です

 暗号化は偽造攻撃を防ぐことができます、一度のurlは一度だけ確認できます、ユーザーにバインドされています。urlの生成: 随機なキーを生成するためにUUIDを使用できます。

数字署名 = MD5(ユーザー名+'$'+有効期限+‘$'+キーkey)

データベースのフィールド(ユーザー名(主キー),キーkey,有効期限)

urlパラメータ(ユーザー名,数字署名) ,キーkeyの生成:ユーザーがパスワードを再設定するたびに、そのユーザーにキーkeyを生成する。

url example: http://localhost:8080/user/reset_password#63;sid=D622D6A23FBF86FFE696B593D55351A54AEAEA77&userName=test4

生成过期时间,生成数字签名,生成url,发送邮件. saveOrUpdate(用户名,密钥key,过期时间)

以下为springMvc代码

@RequestMapping(value = "/user/i_forget_password")
  @ResponseBody
  public Map forgetPass(HttpServletRequest request,String userName){
    Users users = userService.findUserByName(userName);
    Map map = new HashMap<String ,String>();
    String msg = "";
    if(users == null){       //ユーザー名が存在しません
      msg = "ユーザー名が存在しません、ユーザー名を忘れたんですか?"63;";
      map.put("msg",msg);
      return map;
    }
    try{
      String secretKey = UUID.randomUUID().toString(); //キー
      Timestamp outDate = new Timestamp(System.currentTimeMillis();+30*60*1000);//30分後に有効期限切れ
      long date = outDate.getTime();/1000*1000;         //ミリ秒を無視
      users.setValidataCode(secretKey);
      users.setRegisterDate(outDate);
      userService.update(users);  //データベースに保存
      String key = users.getUserName()+"$"+date+"$"+secretKey;
      String digitalSignature = MD5.MD5Encode(key);         //デジタル署名
      String emailTitle = "有方云パスワードリセット";
      String path = request.getContextPath();
      String basePath = request.getScheme();+://"+request.getServerName();+:"+request.getServerPort();+path+"/";
      String resetPassHref = basePath;+"user/reset_password#63;sid="+digitalSignature;+"&userName="+users.getUserName();
      このメールには返信しないでください。以下のリンクをクリックしてパスワードを再設定してください<br/><a href="+resetPassHref; +" target='_BLANK'>パスワードを再設定するためにクリックしてください</a>" +
          "<br/このメールは30分後にリンクが無効になりますので、再びパスワードリセットをリクエストしてください。+key;+"\t"+digitalSignature;
      System.out.print(resetPassHref);
      SendMail.getInstatnce().sendHtmlMail(emailTitle, emailContent, users.getEmail());
      操作成功、パスワードリセットのリンクをあなたのメールアドレスに送信しました。リンクは0分後に無効になりますので、再びリクエストしてください。30分以内にパスワードを再設定してください";
      logInfo(request,userName,"申请找回密码");
    }
      e.printStackTrace();
      msg="メールが存在しませんか?未知のエラー、管理者に連絡してください。";
    }
    map.put("msg",msg);
    return map;
  }

找回链接已经发到邮箱了。进入邮箱点开链接

以下为链接检验代码,验证通过 跳转到修改密码界面,否则跳转到失败界面

@RequestMapping(value = "/user/reset_password",method = RequestMethod.GET)
  public ModelAndView checkResetLink(String sid,String userName){
    ModelAndView model = new ModelAndView("error");
    String msg = "";
    if(sid.equals("") || userName.equals("")){
      msg="リンクが不完全です、再生成してください";
      model.addObject("msg",msg) ;
      logInfo(userName,"パスワードリセットリンクが無効");
      return model;
    }
    Users users = userService.findUserByName(userName);
    if(users == null){
      msg = "リンクが誤りです、一致するユーザーが見つかりません、再申請してパスワードを再設定してください.";
      model.addObject("msg",msg) ;
      logInfo(userName,"パスワードリセットリンクが無効");
      return model;
    }
    Timestamp outDate = users.getRegisterDate();
    if(outDate.getTime() <= System.currentTimeMillis()){     //期限が切れました
      msg = "リンクが期限切れです、再申請してパスワードを再設定してください.";
      model.addObject("msg",msg) ;
      logInfo(userName,"パスワードリセットリンクが無効");
      return model;
    }
    String key = users.getUserName()+"$"+outDate.getTime()/1000*1000+"$"+users.getValidataCode();     //デジタル署名
    String digitalSignature = MD5.MD5Encode(key);
    System.out.println(key+"\t"+digitalSignature);
    if(!digitalSignature.equals(sid)) {
      msg = "リンクが不正です、期限が切れていませんか?&#"63;再申請してください";
      model.addObject("msg",msg) ;
      logInfo(userName,"パスワードリセットリンクが無効");
      return model;
    }
    model.setViewName("user/reset_password"); //変更パスワードの画面に戻ります
    model.addObject("userName",userName);
    return model;
  }

補足1:Timestamp 型オブジェクトがデータに保存される際に、ミリ秒精度が失われます。例えば、2013-10-08 10:29:10.234 mysql データベースに保存するときに、次のように変わります 2013-10-08 10:29:10.0。時間が異なります、sid が一致する時は等しくなりません。したがって、精度を無視する操作を行いました。

補足2:linux 以下のタイトルの中文乱码を解決する

sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
mailMessage.setSubject(MimeUtility.encodeText(mailInfo.getSubject(), "UTF"-8"B"      //linux メールタイトルの乱码を解決する

補足3:なぜ直接 sid を user テーブルに挿入しないのですか。確認時に sid を比較するだけで大丈夫です。

これで本文のすべてが終わりました。皆様の学習に役立てば幸いです。また、呐喊教程を多くのサポートをお願いします。

声明:本文の内容はインターネットから取得しており、著作権者はすべての権利を保有しています。コンテンツはインターネットユーザーによって自発的に貢献し、アップロードされました。当サイトは所有権を持ちません。また、人工編集は行われていません。著作権に関する問題がある場合は、以下のメールアドレスにご連絡ください:notice#oldtoolbag.com(メール送信時は、#を@に置き換えてください。報告を行い、関連する証拠を提供してください。一旦確認がとりたいと、当サイトは直ちに侵害する疑いのある内容を削除します。)

おすすめ