1. Preparation before using the integration API
The one-time authentication key, the authentication code used by BaroPAM, is written based on Java, so the latest JDK 6.x or higher must be installed. If it is not installed, you need to install the latest JDK. If it is not installed(npm install java), you need to install the latest JDK.
Verify JDK installation)
[root]# rpm -qa | grep java java-1.4.2-gcj-compat-devel-1.4.2.0-40jpp.115 java-1.7.0-openjdk-javadoc-1.7.0.131-2.6.9.0.el5_11 java-1.4.2-gcj-compat-1.4.2.0-40jpp.115 java-1.4.2-gcj-compat-javadoc-1.4.2.0-40jpp.115 bsh-javadoc-1.3.0-9jpp.1 tzdata-java-2016j-1.el5 java-1.6.0-openjdk-devel-1.6.0.41-1.13.13.1.el5_11 java-1.7.0-openjdk-src-1.7.0.131-2.6.9.0.el5_11 java-1.4.2-gcj-compat-src-1.4.2.0-40jpp.115 java-1.7.0-openjdk-1.7.0.131-2.6.9.0.el5_11 java-1.7.0-openjdk-demo-1.7.0.131-2.6.9.0.el5_11 java-1.4.2-gcj-compat-devel-1.4.2.0-40jpp.115 xmlrpc-javadoc-2.0.1-3jpp.1 gcc-java-4.1.2-55.el5 java-1.6.0-openjdk-1.6.0.41-1.13.13.1.el5_11 java-1.7.0-openjdk-devel-1.7.0.131-2.6.9.0.el5_11 |
Check the JDK installation directory)
[root]# env | grep JAVA_HOME JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.121.x86_64 |
Java version check)
[root]# java -version java version "1.7.0_121" OpenJDK Runtime Environment (rhel-2.6.8.1.el5_11-x86_64 u121-b00) OpenJDK 64-Bit Server VM (build 24.121-b00, mixed mode) |
2. BaroPAM integration API
2.1 Login screen
1) BaroPAM login screen example)
2) Authentication key verification part
The API for verifying the one-time authentication key entered in the password field when logging in to the application is provided as "barokey.jar".
You can locate "barokey.jar" in the lib directory of WAS (Web Application Server) or set the class-path to include the directory where "barokey.jar" exists.
Insert the following code into a program that verifies the one-time authentication key, which is the password entered when logging in to the application.
... import com.barokey.barokey; ... Login-ID validation is checked and authentication key verification module is called only in case of success. ... boolean bauth_key = barokey.verifyKEYL(String login_id, String phone_no, String cycle_time, tkey); boolean bauth_key = barokey.verifyKEYL(String login_id, String phone_no, String cycle_time, String key_method, String tkey); if (bauth_key == true) { // Verification success } else { // Verification failure } ... |
Parameter | Description | Etc |
login_id | Set the ID entered in the Login-ID field of the login screen. | |
phone_no | Set smartphone numbers for each user only by numbers. | |
cycle_time | Set the generation cycle (3~60 seconds) of one-time authentication key specified for each user. | |
key_method | Set the one-time authentication key authentication method (app1, app256, app384, app512: app). | |
tkey | Set the one-time authentication key entered in the password on the login screen. | |
If the generation period of the smart phone number for each user and the one-time authentication key designated for each individual is different from the generator of the one-time authentication key, verification may fail because the one-time authentication key is different. You must match the information.
예)
…… let login_id = "mc529@nurit.co.kr"; let phone_no = "01027714076" let cycle_time = "30"; let auth_key = "123456" let java = require("java"); java.classpath.push("barokey.jar"); let instance = java.newInstanceSync("com.barokey.barokey"); let bauth_key = java.callMethodSync(instance, "verifyKEYL", login_id, phone_no, cycle_time, auth_key); if (err) { console.error(err); return; } else if (bauth_key == true) { console.log("Verification success.!!!"); return; } else { console.log("Verification failure.!!!"); return; } …… |
2.2 For Android phone
1) Authentication key generator part
The API that creates the one-time authentication key to be entered in the password field when logging in to the application is provided as "barokey.jar", and when using Eclipse or Android studio, "barokey.jar" must be located in the libs directory.
Insert the following code into a program that creates a one-time authentication key that is a password to enter when logging in to the application.
... import com.barokey.barokey; ... String tkey = barokey.generateKEYL(String login_id, String phone_no, String cycle_time); ... |
Parameter | Description | Etc |
login_id | Set the ID entered in the Login-ID field of the login screen. | |
phone_no | Use the TelephonyManager class to set the smart phone number obtained from inside the app. | |
cycle_time | Set the generation cycle (3~60 seconds) of the one-time authentication key specified for each individual. If the generation period of the one-time authentication key designated for each individual is different, the one-time authentication key may be generated differently. |
Screen example)
Screen Layout Example)
<?xml version="1.0" encoding="utf-8"?> xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/bg_body_default" android:orientation="vertical"> <include android:id="@+id/inc_header" layout="@layout/inc_header" android:layout_width="fill_parent" android:layout_height="@dimen/head_height" /> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="@dimen/body_margin_right_default" android:layout_marginRight="@dimen/body_margin_right_default" android:layout_marginTop="@dimen/head_height"> android:id="@+id/body_frame" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="81dip" android:padding="10dp" android:text="@string/tv_key_vc" android:textColor="@color/text_body_default" android:textSize="20dip" /> <TextView android:id="@+id/tv_auth_key" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="150dip" android:background="@android:color/transparent" android:ems="10" android:gravity="center" android:imeOptions="actionGo" android:inputType="text" android:maxLength="8" android:nextFocusDown="@+id/btn_login" android:singleLine="true" android:text="" android:textAppearance="?android:attr/textAppearanceLarge" android:textColor="@color/text_body_default" android:textSize="65dip" /> <TextView android:layout_width="fill_parent" android:layout_height="1dip" android:layout_gravity="center_horizontal" android:layout_marginLeft="50dip" android:layout_marginRight="50dip" android:layout_marginTop="230dip" android:background="@color/line_text_under" android:visibility="invisible" /> <com.beardedhen.androidbootstrap.BootstrapProgressBar android:id="@+id/progressBar" android:layout_width="fill_parent" android:layout_height="12dip" android:layout_gravity="center_horizontal" android:layout_marginTop="240dip" app:animated="true" app:bootstrapBrand="warning" app:bootstrapProgress="100" app:striped="true" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="260dip" android:orientation="horizontal"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" /> <ImageView android:layout_width="15dip" android:layout_height="15dip" android:layout_gravity="center_vertical|right" android:background="@drawable/ico_countdown" /> <TextView android:id="@+id/tv_remainTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="right|center_vertical" android:paddingLeft="10dip" android:textColor="@color/text_body_guide" android:textSize="17dip" /> </LinearLayout> <TextView android:id="@+id/tv_system_nm" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="315dip" android:text="" android:textColor="@color/text_body_default" android:textSize="18dip" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="380dip" android:text="@string/tv_key_msg_1" android:textColor="@color/text_body_guide" android:textSize="18dip" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="405dip" android:text="@string/tv_key_msg_2" android:textColor="@color/text_body_guide" android:textSize="18dip" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="430dip" android:text="@string/tv_key_msg_3" android:textColor="@color/text_body_guide" android:textSize="18dip" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="490dip" android:orientation="horizontal"> <Button android:id="@+id/btn_update" android:layout_width="fill_parent" android:layout_height="@dimen/btn_height_default" android:layout_weight="1" android:background="@drawable/btn_default_drawable" android:text="@string/btn_upd_del" android:textColor="@color/white" android:textSize="20dip" /> <TextView android:layout_width="6dip" android:layout_height="1dip" android:layout_gravity="center_horizontal" android:background="@android:color/transparent" /> <Button android:id="@+id/btn_reset" android:layout_width="fill_parent" android:layout_height="@dimen/btn_height_default" android:layout_weight="1" android:background="@drawable/btn_default_drawable" android:enabled="false" android:text="@string/btn_reset" android:textColor="@color/white" android:textSize="20dip" /> </LinearLayout> </FrameLayout> </ScrollView> </FrameLayout> |
Program example)
package com.baro.otp.info; import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Vibrator; import android.support.v4.app.ActivityCompat; import android.telephony.TelephonyManager; import android.view.View; import android.view.View.OnClickListener; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.TextView; import com.baro.common.base.BaseActivity; import com.baro.common.base.BaseInterface; import com.baro.common.setting.SettingACT; import com.baro.common.util.Util; import com.baro.pam.R; import com.barokey.barokey; import com.beardedhen.androidbootstrap.BootstrapProgressBar; import java.util.Date; public class OTPCreateACT extends BaseActivity implements BaseInterface, OnClickListener { //public class OTPCreateACT extends AppCompatActivity implements BaseInterface, OnClickListener { private Button btn_setting, btn_share, btn_close, btn_reset, btn_update; private TextView tv_auth_key; private TextView tv_remainTime; private BootstrapProgressBar progressBar; private TextView tv_system_nm; private String intent_reg_dt = "", intent_system_nm = "", intent_login_id = "", intent_cycle_time = ""; private String PhoneNumber = "", SerialNumber = "", AndroID = "", MacAddr = ""; private long createdMillis, remainingSec; private static final int MESSAGE_REFRESH_REMAINING_SECOND = 101; private static final int SENDMESSAGE_INTERVAL = 250; private String[] permission_list = { Manifest.permission.INTERNET, Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE }; @Override public void onCreate(Bundle savedInstanceState) { try { super.onCreate(savedInstanceState); setContentView(R.layout.act_otpcreate); checkPermission(); drawView(); getIntentData(); } catch (Exception e) { e.printStackTrace(); } finally { } } @Override public void onPause() { super.onPause(); if (null != m_handlerProc) { m_handlerProc.removeMessages(MESSAGE_REFRESH_REMAINING_SECOND); } } @Override public void onResume() { super.onResume(); if (null != m_handlerProc) { m_handlerProc.sendEmptyMessageDelayed(MESSAGE_REFRESH_REMAINING_SECOND, SENDMESSAGE_INTERVAL); } } @SuppressLint("HardwareIds") @Override public void drawView() { try { vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); findViewById(R.id.body_frame).setOnClickListener(new OnClickListener() { public void onClick(View v) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } }); tv_system_nm = (TextView) findViewById(R.id.tv_system_nm); tv_system_nm.setOnClickListener(this); tv_auth_key = (TextView) findViewById(R.id.tv_auth_key); tv_auth_key.setFocusable(true); tv_auth_key.setClickable(false); progressBar = (BootstrapProgressBar) findViewById(R.id.progressBar); tv_remainTime = (TextView) findViewById(R.id.tv_remainTime); btn_setting = (Button) findViewById(R.id.btn_setting); btn_setting.setOnClickListener(this); btn_share = (Button) findViewById(R.id.btn_share); btn_share.setOnClickListener(this); ((Button) findViewById(R.id.btn_go_back)).setOnClickListener(this); btn_close = (Button) findViewById(R.id.btn_close); btn_close.setOnClickListener(this); btn_update = (Button) findViewById(R.id.btn_update); btn_update.setOnClickListener(this); btn_reset = (Button) findViewById(R.id.btn_reset); btn_reset.setOnClickListener(this); TelephonyManager systemService = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); assert systemService != null; PhoneNumber = systemService.getLine1Number(); PhoneNumber = PhoneNumber.substring(PhoneNumber.length() - 10, PhoneNumber.length()); PhoneNumber = "0" + PhoneNumber; } catch (SecurityException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { } } public void getIntentData() { try { Intent intent = getIntent(); getDefaultIntent(intent); if (intent.getStringExtra("reg_dt") != null) { intent_reg_dt = intent.getStringExtra("reg_dt").trim(); } if (intent.getStringExtra("system_nm") != null) { intent_system_nm = intent.getStringExtra("system_nm"); } if (intent.getStringExtra("login_id") != null) { intent_login_id = intent.getStringExtra("login_id").trim(); } if (intent.getStringExtra("cycle_time") != null) { intent_cycle_time = intent.getStringExtra("cycle_time").trim(); } if ("".equals(intent_system_nm.trim())) { tv_system_nm.setText("[ " + intent_login_id + " ]"); } else if (!"".equals(intent_system_nm) && (!"".equals(intent_login_id))) { tv_system_nm.setText("[ " + intent_system_nm + " / " + intent_login_id + " ]"); } if (!"".equals(intent_login_id) && !"".equals(PhoneNumber) && (!"".equals(intent_cycle_time))) { onAuthKey(); } else { finish(); } } catch (Exception e) { e.printStackTrace(); } finally { } } @Override public void onClick(View v) { try { switch (v.getId()) { case R.id.btn_setting: // Setting Intent intent = new Intent(this, SettingACT.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); startActivity(intent); //finish(); break; case R.id.btn_share: intent = new Intent(Intent.ACTION_SEND); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.putExtra(Intent.EXTRA_TEXT , getString(R.string.app_share)); intent.putExtra(Intent.EXTRA_TITLE, getString(R.string.app_name )); intent.setType("text/plain"); startActivity(Intent.createChooser(intent, getString(R.string.share_text))); //finish(); break; case R.id.btn_go_back: // go back finish(); break; case R.id.btn_close: // Close moveTaskToBack(true); finish(); android.os.Process.killProcess(android.os.Process.myPid()); break; case R.id.btn_update: // Update intent = new Intent(OTPCreateACT.this, OTPUpdateACT.class); intent.putExtra("reg_dt" , intent_reg_dt ); intent.putExtra("system_nm" , intent_system_nm ); intent.putExtra("login_id" , intent_login_id ); intent.putExtra("cycle_time", intent_cycle_time); startActivity(intent); finish(); break; case R.id.btn_reset: // Reset if (!"".equals(intent_login_id) && !"".equals(PhoneNumber) && (!"".equals(intent_cycle_time))) { onAuthKey(); } else { finish(); } break; } } catch (Exception e) { e.printStackTrace(); } finally { } } public void onAuthKey() { try { tv_auth_key.setText(""); createdMillis = estimateCreatedMillis(intent_cycle_time); tv_auth_key.setText(barokey.generateKEYL(intent_login_id, PhoneNumber, intent_cycle_time)); m_handlerProc.sendEmptyMessageDelayed(MESSAGE_REFRESH_REMAINING_SECOND, SENDMESSAGE_INTERVAL); } catch (Exception e) { e.printStackTrace(); } finally { } } private final Handler m_handlerProc = new Handler() { @Override public void handleMessage(Message message) { switch (message.what) { case MESSAGE_REFRESH_REMAINING_SECOND: try { long cycleMillis = (Long.parseLong(intent_cycle_time) * 1000L); long remainingMillis = estimateRemainingMillis(intent_cycle_time, createdMillis); long remainingSecond = remainingMillis != 0 ? (remainingMillis / 1000L) : 0; if (0 < remainingMillis) { m_handlerProc.sendEmptyMessageDelayed(MESSAGE_REFRESH_REMAINING_SECOND, SENDMESSAGE_INTERVAL); btn_reset.setEnabled(false); } else { m_handlerProc.removeMessages(MESSAGE_REFRESH_REMAINING_SECOND); btn_reset.setEnabled(true); } tv_remainTime.setText(remainingSecond + " " + getString(R.string.remain_time_suffix)); if (0 != cycleMillis) { progressBar.setProgress((int) (((float) remainingMillis / (float) cycleMillis) * 100.0F)); } } catch (Exception e) { e.printStackTrace(); } finally { } break; } } }; public long estimateCreatedMillis(String cycleSecondString) { long remainingMillis = (barokey.getRemainingTime(cycleSecondString) * 1000L) - 200; long cycleMillis = (Long.parseLong(cycleSecondString) * 1000L); long currentMillis = (new Date()).getTime(); long elapsedMillis = cycleMillis - remainingMillis; long createdMillis = currentMillis - elapsedMillis; return createdMillis; } public long estimateRemainingMillis(String cycleSecondString, long createdTime) { long cycleMillis = (Long.parseLong(cycleSecondString) * 1000L); long currentMillis = (new Date()).getTime(); long elapsedMillis = currentMillis - createdTime; long remainingMillis = barokey.getRemainingTime(cycleSecondString) * 1000L; remainingMillis = cycleMillis > elapsedMillis ? remainingMillis : 0; remainingMillis = remainingMillis >= cycleMillis ? 0 : remainingMillis; return remainingMillis; } public void checkPermission() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return; for(String permission : permission_list) { int permssionCheck = checkCallingOrSelfPermission(permission); if (permssionCheck == PackageManager.PERMISSION_DENIED) { ActivityCompat.requestPermissions(this, permission_list, 0); } } } public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == 0) { for(int ii = 0; ii < grantResults.length; ii++) { if (grantResults[ii] != PackageManager.PERMISSION_GRANTED) { Util.MsgToast(OTPCreateACT.this, getString(R.string.msg_security_set), 0); finish(); } } } } } |
2.3 For iPhone
1) Authentication key generator part
The API for creating a one-time authentication key to be entered in the password field when logging in to the application is provided as "libbaroutil.a", and this file is a library file for NSObject Interface that includes libraries related to barokey, barocrypt, and base64.
Library files are provided in two types. XCode's iPhone simulator and iPhone use are changed to libbaroutil.a as needed.
- libbaroutil.a.iphone : for iPhone
- libbaroutil.a.simul : for iPhone simulator
This file is registered and used when setting the XCode project as follows.
BaroPAM related API is as follows. The function is composed of C function interface, so the data type of the input value is expressed in C function style. The source of the usage example is the code written with iOS swift 5.0 or higher.
generateKEYL function
This is a function that creates a one-time authentication key used when logging in/authentication to an application.
Input variable | const char *login_id | Set the ID entered in the Login-ID field of the login screen. |
const char *phone_no | This is the user's smartphone number. Unlike the Android app, the user's smartphone number to be used in the server's authentication module is directly registered and managed in the app, without obtaining the user's smartphone number from iOS, and the registered smartphone number is selected and used. | |
const char *cycle_time | It must match the generation cycle (3~60 seconds) of the one-time authentication key designated for each individual. If the generation period of the one-time authentication key designated for each individual is different, the one-time authentication key may be generated differently. |
|
const char *key_method | Set "app512" as the authentication method of the one-time authentication key (app1, app256, app384, app512: app). | |
Return value | One-time auth key | Returns the generated one-time authentication key. |
Example of use in swift 5.0 or higher)
private func makeOtpInfo() { let loginid = _otp?.LOGIN_ID ?? "mc529@hanmail.net" let tel = _otp?.PHONE_NO ?? "01027714076" let time = (_otp?.CYCLE_TIME ?? "30")! let otpnum = generateKEYL(loginid, tel, time, "app512") _otpInfo.text = "[ \(_otp?.SYSTEM_NM ?? "")/\(_otp?.LOGIN_ID ?? "") ]" let otpnumStr = String(cString: otpnum!) let start = otpnumStr.index(otpnumStr.startIndex, offsetBy: 0) let end = otpnumStr.index(otpnumStr.startIndex, offsetBy: 3) let start2 = otpnumStr.index(otpnumStr.startIndex, offsetBy: 3) let end2 = otpnumStr.index(otpnumStr.startIndex, offsetBy: 6) _tfOTP.text = otpnumStr[start..<end] + " " + otpnumStr[start2..<end2] var step = 0 self._progress.progress = 0 self._btnReset.isEnabled = false self._btnReset.backgroundColor = uicolorFromHex(rgbValue: 0xA0AAB4) let remain = getRemainingTime(_otp?.CYCLE_TIME ?? "30") let cycle_time = Int(self._otp!.CYCLE_TIME) _timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { _timer in let change: Float = Float(Double(remain - step - 1) / Double(cycle_time!)) print("---- \(remain),\(change),\(step)") self._progress.progress = change step += 1 self._remainTime.text = String(remain - step) + " " + "TIME".localized if step == remain { self._timer?.invalidate() self._btnReset.isEnabled = true self._btnReset.backgroundColor = uicolorFromHex(rgbValue: 0x1B90FF) } }) } |
Screen example)
Screen Layout Example)
It means Storyboard. For the meaning of each parameter, refer to developer.apple.com.
<!--Create View Controller--> <scene sceneID="xJv-bd-Ejb"> <objects> <viewController storyboardIdentifier="CreateOTP" id="BPh-Tl-Gd5" customClass="OTPCreateViewController" customModule="BaroPAM" customModuleProvider="target" sceneMemberID="viewController"> <layoutGuides> <viewControllerLayoutGuide type="top" id="TF9-Et-51n"/> <viewControllerLayoutGuide type="bottom" id="rXs-zr-mnc"/> </layoutGuides> <view key="view" contentMode="scaleToFill" id="DbI-ks-whW"> <rect key="frame" x="0.0" y="0.0" width="375" height="812"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" text="일회용 인증키" textAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="O0T-Oa-9fL"> <rect key="frame" x="0.0" y="125" width="375" height="40"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <color key="textColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> <fontDescription key="fontDescription" name="SpoqaHanSans-Regular" family="SpoqaHanSans" pointSize="17"/> <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> </textView> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="12345678" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="y9V-iO-Xec"> <rect key="frame" x="19" y="204" width="336" height="52"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <fontDescription key="fontDescription" name="SpoqaHanSans-Regular" family="SpoqaHanSans" pointSize="50"/> <textInputTraits key="textInputTraits"/> </textField> <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wn5-JQ-qp2"> <rect key="frame" x="23" y="683" width="160" height="43"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/> <fontDescription key="fontDescription" name="SpoqaHanSans-Regular" family="SpoqaHanSans" pointSize="17"/> <state key="normal" title="Update/Delete"> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> </state> <connections> <action selector="onEdit:" destination="BPh-Tl-Gd5" eventType="touchUpInside" id="Lq0-gt-fdh"/> <action selector="onOk:" destination="BYZ-38-t0r" eventType="touchUpInside" id="ya1-b8-A5Q"/> </connections> </button> <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="phw-d7-Zsz"> <rect key="frame" x="199" y="683" width="160" height="43"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMinY="YES"/> <fontDescription key="fontDescription" name="SpoqaHanSans-Regular" family="SpoqaHanSans" pointSize="17"/> <state key="normal" title="Reset"> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> </state> <connections> <action selector="onReset:" destination="BPh-Tl-Gd5" eventType="touchUpInside" id="2is-dP-y2P"/> </connections> </button> <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KTy-6U-0mm"> <rect key="frame" x="0.0" y="0.0" width="375" height="70"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <subviews> <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5ZR-gQ-4P5"> <rect key="frame" x="283" y="34" width="31" height="31"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> <inset key="imageEdgeInsets" minX="3" minY="3" maxX="3" maxY="3"/> <state key="normal" image="btn_share.png"/> <connections> <action selector="onShare:" destination="BPh-Tl-Gd5" eventType="touchUpInside" id="rVd-lW-j3A"/> </connections> </button> <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uD6-U2-2w3"> <rect key="frame" x="322" y="34" width="33" height="32"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> <inset key="imageEdgeInsets" minX="3" minY="3" maxX="3" maxY="3"/> <state key="normal" image="btn_setting.png"/> <connections> <action selector="onSetting:" destination="BPh-Tl-Gd5" eventType="touchUpInside" id="Qhc-bj-CHe"/> </connections> </button> <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="btn_prev.png" translatesAutoresizingMaskIntoConstraints="NO" id="cZQ-Jb-Iuv"> <rect key="frame" x="19" y="35" width="31" height="31"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" heightSizable="YES"/> </imageView> <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="logo_barootp.png" translatesAutoresizingMaskIntoConstraints="NO" id="vWu-o6-6az"> <rect key="frame" x="115" y="38" width="145" height="25"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> </imageView> </subviews> <color key="backgroundColor" red="0.10588235294117647" green="0.56470588235294117" blue="1" alpha="1" colorSpace="calibratedRGB"/> </view> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" editable="NO" text="유효시간 내에 인증키를 입력하세요. 시간을 초과한 경우 Reset 버튼을 클릭하여 인증키를 재생성 하세요." textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="s4z-fe-3rj"> <rect key="frame" x="49" y="585" width="276" height="112"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <color key="textColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="calibratedRGB"/> <fontDescription key="fontDescription" name="SpoqaHanSans-Regular" family="SpoqaHanSans" pointSize="17"/> <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> </textView> <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" fixedFrame="YES" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="eFk-qb-ugh"> <rect key="frame" x="52" y="274" width="270" height="2"/> <autoresizingMask key="autoresizingMask" widthSizable="YES"/> </progressView> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="ico_countdown.png" translatesAutoresizingMaskIntoConstraints="NO" id="UC7-dN-2I6"> <rect key="frame" x="250" y="284" width="15" height="15"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> </imageView> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c11-3a-nD8"> <rect key="frame" x="270" y="281" width="52" height="21"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <fontDescription key="fontDescription" name="SpoqaHanSans-Regular" family="SpoqaHanSans" pointSize="17"/> <color key="textColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="[emplus/david.kscho@empluses.com]" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FZO-er-yGs"> <rect key="frame" x="23" y="318" width="332" height="30"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <fontDescription key="fontDescription" name="SpoqaHanSans-Regular" family="SpoqaHanSans" pointSize="17"/> <nil key="highlightedColor"/> </label> </subviews> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> </view> <connections> <outlet property="_backView" destination="cZQ-Jb-Iuv" id="hti-Le-Rra"/> <outlet property="_btnReset" destination="phw-d7-Zsz" id="hVD-Q9-8Xq"/> <outlet property="_btnUpdate" destination="wn5-JQ-qp2" id="o6G-9e-g0S"/> <outlet property="_otpInfo" destination="FZO-er-yGs" id="d1r-2i-KX2"/> <outlet property="_progress" destination="eFk-qb-ugh" id="csW-nT-cyw"/> <outlet property="_remainTime" destination="c11-3a-nD8" id="b6H-g5-lXA"/> <outlet property="_tfOTP" destination="y9V-iO-Xec" id="loX-6A-goi"/> </connections> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="GRs-8z-hxZ" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> <point key="canvasLocation" x="2948" y="440"/> </scene> |
Program example)
import UIKit class OTPCreateViewController : UIViewController { @IBOutlet weak var _progress: UIProgressView! @IBOutlet weak var _remainTime: UILabel! @IBOutlet weak var _backView: UIImageView! @IBOutlet weak var _otpInfo: UILabel! @IBOutlet weak var _tfOTP: UITextField! @IBOutlet weak var _btnUpdate: UIButton! @IBOutlet weak var _btnReset: UIButton! @IBAction func onClose(_ sender: Any) { exit(0) } var _timer: Timer? var _otp: OTPEntity? = nil override func viewDidLoad() { super.viewDidLoad() //chagneBackground() initControls() makeTappedView() makeOtpInfo() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if (_otp?.IS_DELETE == 1) { _otp?.IS_DELETE = 0 dismiss(animated: false, completion: nil) } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) } private func initControls() { _btnUpdate.backgroundColor = uicolorFromHex(rgbValue: 0x1B90FF) _btnReset.backgroundColor = uicolorFromHex(rgbValue: 0x1B90FF) super.modalPresentationStyle = .fullScreen } private func chagneBackground() { // MAIN View Background Change let background = UIImageView(frame: UIScreen.main.bounds) background.image = UIImage(named: "bg_sub.png") self.view.insertSubview(background, at: 0) } private func makeTappedView() { let tap = UITapGestureRecognizer(target: self, action: #selector(OTPCreateViewController.backTapped)) _backView.isUserInteractionEnabled = true _backView.addGestureRecognizer(tap) } private func makeOtpInfo() { let loginid = _otp?.LOGIN_ID ?? "mc529@hanmail.net" let tel = _otp?.PHONE_NO ?? "01027714076" let time = (_otp?.CYCLE_TIME ?? "30")! let otpnum = generateKEYL(loginid, tel, time, "app512") _otpInfo.text = "[ \(_otp?.SYSTEM_NM ?? "")/\(_otp?.LOGIN_ID ?? "") ]" let otpnumStr = String(cString: otpnum!) let start = otpnumStr.index(otpnumStr.startIndex, offsetBy: 0) let end = otpnumStr.index(otpnumStr.startIndex, offsetBy: 3) let start2 = otpnumStr.index(otpnumStr.startIndex, offsetBy: 3) let end2 = otpnumStr.index(otpnumStr.startIndex, offsetBy: 6) _tfOTP.text = otpnumStr[start..<end] + " " + otpnumStr[start2..<end2] var step = 0 self._progress.progress = 0 self._btnReset.isEnabled = false self._btnReset.backgroundColor = uicolorFromHex(rgbValue: 0xA0AAB4) let remain = getRemainingTime(_otp?.CYCLE_TIME ?? "30") let cycle_time = Int(self._otp!.CYCLE_TIME) _timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { _timer in let change: Float = Float(Double(remain - step - 1) / Double(cycle_time!)) print("---- \(remain),\(change),\(step)") self._progress.progress = change step += 1 self._remainTime.text = String(remain - step) + " " + "TIME".localized if step == remain { self._timer?.invalidate() self._btnReset.isEnabled = true self._btnReset.backgroundColor = uicolorFromHex(rgbValue: 0x1B90FF) } }) } @objc func backTapped(tabGestureRecg: UITapGestureRecognizer) { dismiss(animated: false, completion: nil) // } @IBAction func onEdit(_ sender: Any) { switchScreen("SystemOTP", { _ = ($0 as! OTPInfoSaveViewController).changeMode(.EDIT).setOtp(_otp!).setParent(self) }) } @IBAction func onReset(_ sender: Any) { makeOtpInfo() } func setOtp(_ otp: OTPEntity) { _otp = otp print("--------> \(otp.REG_DT), \(otp.LOGIN_ID), \(otp.SYSTEM_NM), \(otp.CYCLE_TIME)") } @IBAction func onSetting(_ sender: Any) { switchScreen("Settings") } @IBAction func onShare(_ sender: Any) { } } |
'▶ BaroSolution > 가이드' 카테고리의 다른 글
BaroPAM solution's API guide for no-remember passwords(dll) (0) | 2021.02.13 |
---|---|
BaroPAM solution's API guide for no-remember passwords(C#) (0) | 2021.02.05 |
BaroPAM solution's API guide for no-remember passwords(Java) (0) | 2021.02.01 |
기억할 필요 없는 비밀번호를 위한 BaroPAM의 API 가이드(NodeJS 웹 서버) (0) | 2021.01.29 |
Oracle 사용자를 위한 추가 보안 계층을 추가하여 보안을 강화하기 위한 BaroPAM의 API 가이드 (0) | 2021.01.07 |