如何在Java中用API密钥进行认证

756 阅读3分钟

在Java中用API Key进行认证

通常情况下,在网络应用中,我们会使用一个用户名(电子邮件ID/登录名)和一个密码来登录。我们也可以通过使用APIKey来实现安全登录。让我们看看什么是APIKey。API密钥是一个唯一的标识符,用于验证请求,如果有几个用户,他们的用户名或电子邮件ID可以与当前日期和一个安全代码结合起来,只为该项目使用md5机制,我们可以创建APIKey并可以在数据库中维护。让 我们看看创建APIKey和将其插入数据库的方法。

项目实例

MySQL表结构。

-- Sample table named users is available
CREATE TABLE `users` (
  `userId` int(11) NOT NULL AUTO_INCREMENT,
  `loginId` varchar(20) DEFAULT NULL,
  apiKey varchar(255) DEFAULT NULL,
  PRIMARY KEY (`userId`)
);
-- insert 2 records
insert into users (loginId) values ('geeka@gmail.com');
insert into users (loginId) values ('geekb@gmail.com');

现在让我们看看创建API密钥并将其更新到 "用户"(MySQL)表中的示例java程序

Java

import static java.nio.charset.StandardCharsets.UTF_8;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class CreateAndUpdateAPIKey {
	Connection conn;
	// To generate MD5 hashvalue
	public String generateMD5Hashvalue(String userName)
	{
		LocalDate dateObj = LocalDate.now();
		DateTimeFormatter formatter
			= DateTimeFormatter.ofPattern("yyyyMMdd");
		String date = dateObj.format(formatter);

		MessageDigest md;
		try {
			md = MessageDigest.getInstance("MD5");
		}
		catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException(e);
		}
		String secretPhase
			= "geeks"; // exclusively to set for geeks
		System.out.println("Current Date : " + date);
		System.out.println("Login Id : " + userName);
		System.out.println("Secret Phase : " + secretPhase);

		// By using the current date, userName(emailId) and
		// the secretPhase , it is generated
		byte[] hashResult
			= md.digest((date + userName + secretPhase)
							.getBytes(UTF_8));
		// convert the value to hex
		String password = bytesToHex(hashResult);
		System.out.println("Generated password.."
						+ password);

		return password;
	}
	private String bytesToHex(byte[] bytes)
	{
		StringBuilder sb = new StringBuilder();
		for (byte b : bytes) {
			sb.append(String.format("%02x", b));
		}
		return sb.toString();
	}

	public static void main(String[] args)
	{
		// let us assume there is a table 'users' available
		// By passing as an argument, we can have that for
		// any table
		new CreateAndUpdateAPIKey("users");
	}

	public CreateAndUpdateAPIKey(String tableName)
	{
		try {
			// connecting to mySQL
			Class.forName("com.mysql.jdbc.Driver")
				.newInstance();
			String url
				= "jdbc:mysql://localhost/geeksforgeeks?useUnicode=true&characterEncoding=utf-8";
			conn = DriverManager.getConnection(url, "root",
											"admin");
			doSelectAndUpdate(tableName);
			conn.close();
		}
		catch (ClassNotFoundException ex) {
			System.err.println(ex.getMessage());
		}
		catch (IllegalAccessException ex) {
			System.err.println(ex.getMessage());
		}
		catch (InstantiationException ex) {
			System.err.println(ex.getMessage());
		}
		catch (SQLException ex) {
			System.err.println(ex.getMessage());
		}
	}

	private void doSelectAndUpdate(String tableName)
	{
		doSelect(tableName);
	}

	private void doSelect(String tableName)
	{
		String query = null, userName = null;
		// Query the respective table. If multiple tables
		// are possible, then we should have separate if or
		// switch statements
		query = "SELECT * FROM users";

		try {
			Statement st = conn.createStatement();
			ResultSet rs = st.executeQuery(query);
			while (rs.next()) {
				// loginId is the unique column to identify
				// the user
				userName = rs.getString("loginId");
				// Get the MD5 value and get as password
				String password
					= generateMD5Hashvalue(userName);
				// update the password
				doUpdate(password, userName, tableName);
				System.out.println(userName + ":"
								+ password);
			}
		}
		catch (SQLException ex) {
			System.err.println(ex.getMessage());
		}
	}

	private void doUpdate(String apiKey, String userName,
						String tableName)
	{
		System.out.print("\n[Performing UPDATE] ... ");
		try {
			Statement st = conn.createStatement();
		
			// Use the generated password for apiKey
			String sqlUpdate = null;
			sqlUpdate = "UPDATE users "
						+ "SET apikey = ? "
						+ "WHERE loginId = ?";

			PreparedStatement pstmt
				= conn.prepareStatement(sqlUpdate);

			pstmt.setString(1, apiKey);
			pstmt.setString(2, userName);

			int rowAffected = pstmt.executeUpdate();
			System.out.println(String.format(
				"Row affected %d", rowAffected));
		}
		catch (SQLException ex) {
			System.err.println(ex.getMessage());
		}
	}
}

在执行上述程序时,我们可以看到下面的输出 我们也可以看到API密钥在MySQL中的更新情况。

现在让我们尝试使用登录ID和apiKey登录到样本中。最重要的是apiKey将在每天的基础上因为日期而被改变。为了实现这一点,这段java代码需要作为 "CRON "作业放在Linux服务器上。我们可以有一个JSP页面的样本,在那里我们应该有键入loginId和apiKey的规定。

HTML

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Login Form With APIKey</title>
</head>
<body>
	<div align="center">
		<h1>Login Form - API KEY</h1>
		<form action="<%=request.getContextPath()%>/login" method="post">
			<table style="with: 100%">
				<tr>
					<td>Login</td>
					<td><input type="text" name="loginId" /></td>
				</tr>
				<tr>
					<td>APIKEY</td>
					<td><input type="password" name="apiKey" /></td>
				</tr>

			</table>
			<input type="submit" value="Submit" />
			
		</form>
	</div>
</body>
</html>

一旦收到信息,它将被存储在Bean中并得到验证。让我们来看看验证的部分。

LoginWithAPIKeyDao.java

Java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.gfg.login.bean.LoginBean;

public class LoginWithAPIKeyDao {

	public boolean validate(LoginBean loginBean)
		throws ClassNotFoundException
	{
		boolean status = false;

		Class.forName("com.mysql.jdbc.Driver");

		try {
			Connection connection = DriverManager.getConnection(
				"jdbc:mysql://localhost:3306/geeksforgeeks?useSSL=false",
				"root", "admin");
			// We have to query the users table with the
			// passed information
			PreparedStatement preparedStatement
				= connection.prepareStatement(
					"select * from users where loginId = ? and apiKey = ?");
			preparedStatement.setString(
				1, loginBean.getLoginId());
			preparedStatement.setString(
				2, loginBean.getApiKey());

			ResultSet rs = preparedStatement.executeQuery();
			// For the given query, if there is a record
			while (rs.next()) {
				status = true; // make the status to true
			}
		}
		catch (SQLException e) {
			// process sql exception
			displaySQLException(e);
		}
		return status;
	}

	private void displaySQLException(SQLException ex)
	{
		// for (Throwable e : ex) {
		if (ex instanceof SQLException) {
			ex.printStackTrace(System.err);
			System.err.println(
				"SQLState: "
				+ ((SQLException)ex).getSQLState());
			System.err.println(
				"Error Code: "
				+ ((SQLException)ex).getErrorCode());
			System.err.println("Message: "
							+ ex.getMessage());
			Throwable t = ex.getCause();
			while (t != null) {
				System.out.println("Cause: " + t);
				t = t.getCause();
			}
		}
		// }
	}
}

然后,它将被重定向到成功页面或进一步的机制。

总结

在这篇文章中,我们看到了如何通过使用MD5 机制来生成APIKey,以及如何使用loginId/apiKey来登录到一个应用程序。