Web 開発再入門 #11 ― モデル処理
fmockup
はじめに
Web アプリケーションのサーバー・サイドを開発します。
MVC の Model 部分となります。
MVC:Model View Controller
画面ショット
ログイン画面で認証 Web API を呼び出したとき、Web API の Model 部分でエラーを出しています。
フォルダー・ファイル構成
D:\
└ Developments\
└ Workspace\
└ fmockup\
├ build\
├ sql\
├ src\
│ └ main\
│ ├ java\
│ │ └ cn\
│ │ └ com\
│ │ └ xxxx\
│ │ └ fmockup\
│ │ ├ action\
│ │ ├ controller\
│ │ ├ customizer\
│ │ ├ entity\
│ │ ├ mapper\
│ │ ├ response\
│ │ ├ service\
│ │ │ └ SessionAuthService.java ← コレ
│ │ ├ util\
│ │ │ └ CryptoUtil.java ← コレ
│ │ ├ validator\
│ │ └ validator_order\
│ └ resources\
├ vue-vite\
└ WinSW.NET-nnn\
ファイルの文字コード
基本的に Eclipse でファイルを作成するので、あまり意識したことがありません。
多分、Unix 改行(LF)なのだと思います。
ファイルの作成
- Eclipse で、“SessionAuthService.java”、“CryptoUtil.java” を作成する。
SessionAuthService.java
・・・ package cn.com.xxxx.fmockup.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import cn.com.xxxx.fmockup.entity.SessionAuthEntity; import cn.com.xxxx.fmockup.mapper.SessionAuthMapper; import cn.com.xxxx.fmockup.util.CryptoUtil; import cn.com.xxxx.fmockup.util.LogUtil; import cn.com.xxxx.fmockup.util.MessageUtil; import cn.com.xxxx.fmockup.util.PropertyUtil; import cn.com.xxxx.fmockup.validator.SessionAuthValidator; /** * Session Auth Service * It processes login data. */ @Service public class SessionAuthService { @Autowired private SessionAuthMapper mapper; /** * Session Auth Service * It processes login data. */ public SessionAuthEntity searchOneUser(SessionAuthValidator validator) throws Exception { // // If an error occurs in this process, it must output a blurred explanation in error message. // // Get Values from Database SessionAuthEntity entity; try { entity = mapper.searchOneUser(validator); } catch (Exception ex) { LogUtil.info("searchOneUser : '" + ex.getMessage() + "'"); throw new Exception(MessageUtil.COMMON_ERROR_STRING_UNKNOWN_TROUBLE_HAS_OCCURRED); } if (entity == null) { LogUtil.info("searchOneUser : 'User does not exists.'"); // A true problem explanation throw new Exception(MessageUtil.getMessage(MessageUtil.LOGIN_ERROR_TITLE_USER_ID_OR_PASSWORD_IS_NOT_CORRECT)); // A blurred explanation } // Check Retry Count if (entity.getFailedCount() >= PropertyUtil.getLoginRetryCount()) { LogUtil.info("searchOneUser : 'Retry Count is overed by maximum count.'"); // A true problem explanation throw new Exception(MessageUtil.getMessage(MessageUtil.LOGIN_ERROR_TITLE_USER_ID_OR_PASSWORD_IS_NOT_CORRECT)); // A blurred explanation } // Check Match Password String password; try { password = CryptoUtil.decrypt(entity.getPasswordAes()); // ★★★ ↑ CryptoUtil.java ★★★ } catch (Exception ex) { LogUtil.info("searchOneUser : '" + ex.getMessage() + "'"); // A true problem explanation throw new Exception(MessageUtil.getMessage(MessageUtil.LOGIN_ERROR_TITLE_USER_ID_OR_PASSWORD_IS_NOT_CORRECT)); // A blurred explanation } if (! password.equals(validator.getPassword())) { try { mapper.updateUserFailedCount(entity.getUserId()); } catch (Exception ex) { LogUtil.info("searchOneUser : '" + ex.getMessage() + "'"); throw new Exception(MessageUtil.COMMON_ERROR_STRING_UNKNOWN_TROUBLE_HAS_OCCURRED); } LogUtil.info("searchOneUser : 'Password is not correct.'"); // A true problem explanation throw new Exception(MessageUtil.getMessage(MessageUtil.LOGIN_ERROR_TITLE_USER_ID_OR_PASSWORD_IS_NOT_CORRECT)); // A blurred explanation } // // Because authorization process is already ended, // so if an error occurs in this process, it can output a true problem explanation in error message. // // Set Values to Database int count; try { count = mapper.resetUserFailedCount(entity.getUserId()); } catch (Exception ex) { LogUtil.info("searchOneUser : '" + ex.getMessage() + "'"); throw new Exception(MessageUtil.COMMON_ERROR_STRING_UNKNOWN_TROUBLE_HAS_OCCURRED); } if (count == 0) { LogUtil.info("searchOneUser : 'This Account does not exist.'"); throw new Exception(MessageUtil.getMessage(MessageUtil.LOGIN_ERROR_TITLE_THIS_ACCOUNT_DOES_NOT_EXIST)); } else if (count > 1) { LogUtil.info("searchOneUser : 'Assertion : Invalid count of manipulate data.'"); throw new Exception(MessageUtil.COMMON_ERROR_STRING_UNKNOWN_TROUBLE_HAS_OCCURRED); } return entity; } public void searchOneUserForSession(String userId, String tranName) throws Exception { // // Because authorization process is already ended, // so if an error occurs in this process, it can output a true problem explanation in error message. // // Get Values from Database SessionAuthEntity entity; try { entity = mapper.searchOneUserForSession(userId); } catch (Exception ex) { LogUtil.info("searchOneUserForSession : '" + ex.getMessage() + "'"); throw new Exception(MessageUtil.COMMON_ERROR_STRING_UNKNOWN_TROUBLE_HAS_OCCURRED); } if (entity == null) { LogUtil.info("searchOneUserForSession : 'Yout Account does not exist.'"); throw new Exception(MessageUtil.getMessage(MessageUtil.USER_ERROR_TITLE_THIS_USER_DOES_NOT_EXIST)); } // Check Account Is Locked or Not if (entity.getUserLockedF().equals("Y")) { LogUtil.info("searchOneUserForSession : 'Your Account was locked. Please logout, and try to login again.'"); throw new Exception(MessageUtil.getMessage(MessageUtil.ACCOUNT_ERROR_TITLE_YOUR_ACCOUNT_WAS_LOCKED_PLEASE_LOGOUT_AND_TRY_TO_LOGIN_AGAIN)); } // Check Access Control int count; try { count = mapper.searchOneUserTranCount(userId, tranName); } catch (Exception ex) { LogUtil.info("searchOneUserForSession : '" + ex.getMessage() + "'"); throw new Exception(MessageUtil.COMMON_ERROR_STRING_UNKNOWN_TROUBLE_HAS_OCCURRED); } if (count == 0) { LogUtil.info("searchOneUserForSession : 'Your Account access is restricted.'"); throw new Exception(MessageUtil.getMessage(MessageUtil.ACCOUNT_ERROR_TITLE_YOUR_ACCOUNT_IS_RESTRICTED)); } return; } }
モデルの処理を行います。データベースをアクセスしたり、パスワードをチェックしてエラーを発行したり。CryptoUtil.java・・・ package cn.com.xxxx.fmockup.util; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; /** * Cripto Utility * It encrypts or decrypts data. */ public class CryptoUtil { private static String charset = "utf-8"; /** * Cripto Utility * It encrypts data. */ public static String encrypt(String inString, int charLength) throws Exception { // Feature TODO : Change from "AES" to "AES/GCM/NoPadding". String outString; try { SecretKeySpec key = new SecretKeySpec(PropertyUtil.getCryptoKey().getBytes(charset), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] in = inString.getBytes(charset); byte[] out = cipher.doFinal(in); outString = new String(bin2hex(out)); } catch (Exception e) { throw new Exception("Eecrypt trouble has occurred."); } int length = 16 * ( ( charLength * 6 / 16 ) + 1 ) * 2; // Assertion if (outString.length() > length) { throw new Exception("Assertion : Invalid encrypt length (" + String.valueOf(outString.length()) + " > " + String.valueOf(length) + ")"); } return outString; } /** * Cripto Utility * It decrypts data. */ public static String decrypt(String inString) throws Exception { String outString; try { SecretKeySpec key = new SecretKeySpec(PropertyUtil.getCryptoKey().getBytes(charset), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, key); byte[] in = hex2bin(inString); byte[] out = cipher.doFinal(in); outString = new String(out, charset); } catch (Exception ex) { throw new Exception("Decrypt trouble occurred."); } return outString; } // bin to hex private static String bin2hex(byte[] data) { StringBuffer sb = new StringBuffer(); for (byte b : data) { String s = Integer.toHexString(0xff & b); if (s.length() == 1) { sb.append("0"); } sb.append(s); } return sb.toString(); } // hex to bin private static byte[] hex2bin(String hex) { byte[] bytes = new byte[hex.length() / 2]; for (int index = 0; index < bytes.length; index++) { bytes[index] = (byte) Integer.parseInt(hex.substring(index * 2, (index + 1) * 2), 16); } return bytes; } }
パスワードのデクリプト(復号化)やエンクリプト(暗号化)の処理を行います。ログイン時においては、データベースの暗号化されたパスワードをデクリプト(復号化)して、ログイン画面のパスワードと一致するか否かを確認します。
参考
Service