0
0

Web 開発再入門 #11 ― モデル処理

Last updated at Posted at 2024-04-28

Web 開発再入門 #11 ― モデル処理

fmockup

はじめに

Web アプリケーションのサーバー・サイドを開発します。
MVC の Model 部分となります。

MVC:Model View Controller

画面ショット

ログイン画面で認証 Web API を呼び出したとき、Web API の Model 部分でエラーを出しています。

Java-fmockup_15-loginVerificationError.jpg

フォルダー・ファイル構成

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)なのだと思います。

ファイルの作成

  1. 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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0