Ch10-4 : Auth

[Auth]
承襲上一個小節的註冊,這個小節會說明,註冊認證信的實作,經由上一節的介紹,會Play各種操作更為熟悉,這個小節一樣切開成小功能,依序完成這些小功能後,就可以完成認證信的驗證功能了。

  • Step1 : 檢查認證是否存在
  • Step2 : 檢查會員是否已經認證過
  • Step3 : 檢查連結是否使用過
  • Step4 : 檢查是否有逾期
  • Step5 : 檢查通過,開始更新與新增相關表單
  • Step5.1 : 更新會員認證表單
  • Step5.2 : 更新會員表單
  • Step5.3 : 新增會員紀錄表單

Stop 0
回到WebController,我們基本上的認證信程式會是這個流程,下面的Step會依序講解認證步驟。
path : /app/controllers/WebController.java

  /**
   * <pre>
   * 檢查註冊認證信連結
   * 
   * Step1   : 檢查認證是否存在。
   * Step2   : 檢查會員是否已經認證過。
   * Step3   : 檢查連結是否使用過。
   * Step4   : 檢查是否有逾期。
   * Step5   : 檢查通過,開始更新與新增相關表單。
   * Step5.1 : 更新會員認證表單
   * Step5.2 : 更新會員表單
   * Step5.3 : 新增會員紀錄表單
   * 
   * </pre>
   */
  public Result authMember(String auth){

    // 清除暫存錯誤訊息
    flash().clear();

    // Step 1
    MemberToken memberToken = null ;
    try{
     memberToken = webService.getMemberTokenData(auth , MemberTokenType.Signup.toString());
    } catch(Exception e){
      e.printStackTrace();
    }

    if(memberToken == null){
      flash().put("authError", "認證連結有誤,請重新點選信中認證連結,或使用重發認證信,謝謝。");
      play.Logger.warn("memberToken  = " + Json.toJson(memberToken));
      return ok(checkMemberAuth.render());
    }

    // Step 2
    Member member = null;
    try{
      // 認證連結有資料,使用會員編號,查詢會員資料。
     member = webService.findMemberByMemberNo(memberToken.getMemberNo());
    } catch(Exception e){
      e.printStackTrace();
      flash().put("authError", "系統忙碌中,請稍後再次嘗試!");
      return ok(checkMemberAuth.render());
    }

    if(!MemberStatus.S1.getStatus().equals(member.getStatus())){
      flash().put("authError", "您的帳號,已經認證成功,不需再認證,謝謝。");
      play.Logger.warn("member      = " + Json.toJson(member));
      return ok(checkMemberAuth.render());
    }

    // Step 3
    boolean isUse       = memberToken.getIsUse(); // 認證字串是否使用過
    if (isUse){
      flash().put("authError", "該連結已成功認證,不需要再次認證,謝謝。");
      return ok(checkMemberAuth.render());
    } 

    // Step 4
    long    dbTime      = Long.parseLong(memberToken.getDbTime());       // 資料庫時間
    long    expiryDate  = Long.parseLong(memberToken.getExpiryDate());   // 逾期時間
    if(dbTime > expiryDate){
      flash().put("authError", "認證時間已經逾期,請重新使用重發認證信功能謝謝。");
      play.Logger.warn("dbTime      = " + dbTime);
      play.Logger.warn("expiryDate  = " + expiryDate);
      return ok(checkMemberAuth.render());
    } 

    // Step 5
    try{
      int isUpdateMemberTokenOk = webService.updateMemberToken(member.getMemberNo(), MemberTokenType.Signup.toString());
      int isUpdateMemberMainOk = webService.updateMemberToAuthOk(member.getMemberNo());
      int isGenMemberChangeLogOk = webService.genMemberChangeLog(member);
      play.Logger.info("isUpdateMemberAuthOk  = " + isUpdateMemberTokenOk);
      play.Logger.info("isUpdateMemberMainOk  = " + isUpdateMemberMainOk);
      play.Logger.info("isGenMemberChangeLogOk = " + isGenMemberChangeLogOk);
    } catch(Exception e){
      e.printStackTrace();
    }
    return ok(checkMemberAuth.render());
  }


對應的網址。
path : conf/routes

# http://127.0.0.1:9000/web/authMember?auth=XXXXX
GET        /web/authMember              controllers.WebController.authMember(auth : String)



Step1 : 檢查認證是否存在。
當使用者點選註冊認證信回來之後,我們首先要驗證的是,認證字串是否有在我們的資料庫裡。
EX URL : http://127.0.0.1:9000/web/authMember?auth=3464f407e099ab96c9372973c428439db0fa83c0b57c1048fb4a98467db23310
path : /app/controllers/WebController.java

public Result authMember(String auth){

  // 清除暫存錯誤訊息
  flash().clear();

  // Step 1
  MemberToken memberToken = null ;
  try{
   memberToken = webService.getMemberTokenData(auth , MemberTokenType.Signup.toString());
  } catch(Exception e){
    e.printStackTrace();
  }

  if(memberToken == null){
    flash().put("authError", "認證連結有誤,請重新點選信中認證連結,或使用重發認證信,謝謝。");
    play.Logger.warn("memberToken  = " + Json.toJson(memberToken));
    return ok(checkMemberAuth.render());
  }
  ...
}


Controller檢查認證連結memberAuth = webService.getMemberAuthData(auth)時,我們需要新增MemberAuth類別,來對應註冊認證資料。
path : /app/pojo/web/MemberAuth.java

package pojo.web;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class MemberToken {

  private String tokenString;

  private String memberNo;

  private String type;

  private String sendDate;

  private boolean isUse;

  private String createDate;

  private String modifyDate;

  private String expiryDate;

  private String dbTime;

  public String getTokenString() {
    return tokenString;
  }

  public void setTokenString(String tokenString) {
    this.tokenString = tokenString;
  }

  public String getMemberNo() {
    return memberNo;
  }

  public void setMemberNo(String memberNo) {
    this.memberNo = memberNo;
  }

  public String getType() {
    return type;
  }

  public void setType(String type) {
    this.type = type;
  }

  public String getSendDate() {
    return sendDate;
  }

  public void setSendDate(String sendDate) {
    this.sendDate = sendDate;
  }

  public boolean getIsUse() {
    return isUse;
  }

  public void setIsUse(boolean isUse) {
    this.isUse = isUse;
  }

  public String getCreateDate() {
    return createDate;
  }

  public void setCreateDate(String createDate) {
    this.createDate = createDate;
  }

  public String getModifyDate() {
    return modifyDate;
  }

  public void setModifyDate(String modifyDate) {
    this.modifyDate = modifyDate;
  }

  public String getExpiryDate() {
    return expiryDate;
  }

  public void setExpiryDate(String expiryDate) {
    this.expiryDate = expiryDate;
  }

  public String getDbTime() {
    return dbTime;
  }

  public void setDbTime(String dbTime) {
    this.dbTime = dbTime;
  }

  public void setUse(boolean isUse) {
    this.isUse = isUse;
  }

}


檢查連結時,需要查詢member_auth(會員認證資料表),是否有這個認證字串的註冊會員。我們在WebService新增好查詢的行為後,再到XML寫出查詢會員認證的SQL程式。
path : app/services/WebService.java

public interface WebService {
 ...
  /** 驗證會員連結 */
  public MemberToken getMemberTokenData(@Param("token") String token , @Param("type") String type);
 ...
}


查詢的SQL語法。
可以看到,我有多查詢dbTime(資料庫時間),是為了之後驗證會員認證連結時,是否有逾期,需要查詢出目前的資料庫時間,跟認證的逾期日期作為比對的依據。

<!-- 撈出會員認證資訊 -->
<select id="getMemberTokenData" parameterType="String" resultType="pojo.web.MemberToken">
    SELECT *,DATE_FORMAT(NOW(),'%Y%m%d%H%i%s') as dbTime FROM member_token WHERE tokenString=#{token} AND type=#{type}
</select>


測試網址 : http://127.0.0.1:9000/web/authMember?auth=test
檢查頁面


Step2 : 檢查會員是否已經認證過。
有時候會員已經點選過認證信件,而又不小心點選到認證信件時,這時候我們需要提醒使用者,您已經認證過了,不需要在認證了。
note : 以下是會員狀態的說明

S1("1", "尚未認證"), 
S2("2", "已認證"), 
S3("3", "帳號停用");

path : /app/controllers/WebController.java

  ...
  // Step 2
  Member member = null;
  try{
   // 認證連結有資料,使用會員編號,查詢會員資料。
   member = webService.findMemberByMemberNo(memberAuth.getMemberNo());
  } catch(Exception e){
    e.printStackTrace();
    flash().put("authError", "系統忙碌中,請稍後再次嘗試!");
    return ok(checkMemberAuth.render());
  }

  if(!MemberStatus.S1.getStatus().equals(member.getStatus())){
    flash().put("authError", "您的帳號,已經認證成功,不需再認證,謝謝。");
    play.Logger.warn("member      = " + Json.toJson(member));
    return ok(checkMemberAuth.render());
  }
  ...


新增會員狀態的類別。
path : app/pojo/web/MemberStatus.java

package pojo.web;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public enum MemberStatus {

  S1("1", "尚未認證"), 
  S2("2", "已認證"), 
  S3("3", "帳號停用");

  MemberStatus(String status, String statusDesc) {
    this.status = status;
    this.statusDesc = statusDesc;
  }

  public final String status; // 狀態代碼

  public final String statusDesc; // 狀態說明

  public String getStatus() {
    return status;
  }

  public String getStatusDesc() {
    return statusDesc;
  }

}

WebService,新增用會員編號查詢會員資料。
path : app/services/WebService.java

public interface WebService {
 ...
  /** 用會員編號 尋找會員資料 */
  public Member findMemberByMemberNo(String memberNo);
 ...
}


查詢的SQL語法。
會員編號查詢會員資料。

<!-- 根據memberNo查詢會員資料 -->
<select id="findMemberByMemberNo" parameterType="String"
    resultType="pojo.web.Member">
    SELECT * FROM member_main WHERE memberNo = #{memberNo}
</select>


檢查畫面。


Step3 : 檢查連結是否使用過。
當認證連結,已經認證成功後,該連結會失效,需要提示使用者,已經不需要再次認證了。 path : /app/controllers/WebController.java

...
  // Step 3
  boolean isUse       = memberToken.getIsUse(); // 認證字串是否使用過
  if (isUse){
    flash().put("authError", "該連結已成功認證,不需要再次認證,謝謝。");
    return ok(checkMemberAuth.render());
  } 
...


檢查畫面。

Step4 : 檢查是否有逾期。
在Step 1撈出的會員認證資料,我們要檢查是否連結超過時間而失效了,若是超過時間,提示使用者,已經逾期。 path : /app/controllers/WebController.java

  // Step 4
  long    dbTime      = Long.parseLong(memberToken.getDbTime());       // 資料庫時間
  long    expiryDate  = Long.parseLong(memberToken.getExpiryDate());   // 逾期時間
  if(dbTime > expiryDate){
    flash().put("authError", "認證時間已經逾期,請重新使用重發認證信功能謝謝。");
    play.Logger.warn("dbTime      = " + dbTime);
    play.Logger.warn("expiryDate  = " + expiryDate);
    return ok(checkMemberAuth.render());
  }


檢查畫面。


Step5 : 檢查通過,開始更新與新增相關表單。
當以上都檢查通過時,代表該會員符合三個條件,會員尚未認證,認證連結還可以使用,會員認證連結尚未逾期。符合以上條件後,我們會進行三個動作。

Step5.1 : 更新會員認證表單,修改已使用
Step5.2 : 更新會員表單,變成已認證狀態
Step5.3 : 新增會員紀錄表單,寫入上一次會員資料修改前的資料


path : /app/controllers/WebController.java

  // Step 5
  try{
      int isUpdateMemberTokenOk = webService.updateMemberToken(member.getMemberNo(), MemberTokenType.Signup.toString());
    int isUpdateMemberMainOk = webService.updateMemberToAuthOk(member.getMemberNo());
    int isGenMemberChangeLogOk = webService.genMemberChangeLog(member);
    play.Logger.info("isUpdateMemberAuthOk  = " + isUpdateMemberTokenOk);
    play.Logger.info("isUpdateMemberMainOk  = " + isUpdateMemberMainOk);
    play.Logger.info("isGenMemberChangeLogOk = " + isGenMemberChangeLogOk);
  } catch(Exception e){
    e.printStackTrace();
  }
  return ok(checkMemberAuth.render());


WebService,更新會員認證、更新會員資料成為認證狀態、新增會員修改紀錄。
path : app/services/WebService.java

public interface WebService {
 ...
  /** 更新認證連結*/
  public int updateMemberToken(@Param("memberNo") String memberNo , @Param("type") String type);

  /** 更新會員資料*/
  public int updateMemberToAuthOk(String memberNo);

  /** 新增會員紀錄檔資料 */
  public int genMemberChangeLog(@Param("member") Member member);
 ...
}


相關的SQL語法。
Note : 更新會員認證 : 若同個會員有多組尚未認證的資料,需要同時一起更新成使用過,以免使用者點選以前其它的認證信連結。
path : conf/services/WebService.xml

  <!--  更新會員認證-->
  <update id="updateMemberToken">
      UPDATE member_token SET isUse = 1 , modifyDate = DATE_FORMAT(NOW(),'%Y%m%d%H%i%s')
      WHERE memberNo = #{memberNo} AND isUse = 0 AND type = #{type}
  </update>


  <!--  更新會員資料 -->
  <update id="updateMemberToAuthOk">
      UPDATE member_main SET status = '2' , modifyDate = DATE_FORMAT(NOW(),'%Y%m%d%H%i%s')
      WHERE memberNo = #{memberNo}
  </update>


  <!-- 會員記錄檔 -->
  <insert id="genMemberChangeLog" parameterType="pojo.web.Member">
      insert into
      member_main_log(memberNo , email , password , username , createDate)
      values
      ( 
          #{member.memberNo} , 
          #{member.email} ,
          #{member.password},
          #{member.username} ,
          DATE_FORMAT(NOW(), '%Y%m%d%H%i%s')
      );
  </insert>


成功認證畫面。

member_token資料更新。

member_main資料更新。

新增member_main_log會員修改紀錄。


[Final]
這個小節完成了會員認證信的部份,下一個小節,是為了因應,會員忘記去點選認證信,所設計的功能,會跟這個小節頗為類似,若完成之後,可以往下個小節前進,重發認證信功能。

如果有詳細看我的流程步驟,會發現,會員認證的Step 5其實是有問題的,因為我並沒有作任何錯誤的處理,所以特別留下這個地方當作練習,如果其中一部分失敗了,你應該怎樣去處理,這會是一個很好的練習,請嘗試修正看看。

results matching ""

    No results matching ""