如何在React JS中向WSO2 IS 5.9.0发送加密密码并在服务端解密?
Got it, let's tackle how to encrypt the password in your React frontend and decrypt it on WSO2 IS 5.9.0 for the password grant flow. Here's a step-by-step breakdown tailored to your setup:
We'll use RSA asymmetric encryption here—your React app will encrypt the password with a public key, and WSO2 IS will decrypt it using the matching private key. This avoids exposing the plaintext password in transit.
Steps to implement:
- Generate RSA Key Pair: Use OpenSSL to create a 2048-bit RSA key pair (run these commands locally):
# Generate private key openssl genrsa -out wso2-private.key 2048 # Extract public key from private key openssl rsa -in wso2-private.key -pubout -out wso2-public.pem - Add Encryption Library to React: Install
jsencrypt, a lightweight library for RSA encryption in the browser:npm install jsencrypt --save - Encrypt Password in React Code:
Create a utility function to handle encryption, then use it in your token request:
Note: Replaceimport JSEncrypt from 'jsencrypt'; // Utility function to encrypt password const encryptPassword = (plainPassword) => { const encryptor = new JSEncrypt(); // Load your public key (fetch this from a secure backend instead of hardcoding for production) const publicKey = `-----BEGIN PUBLIC KEY----- YOUR_PUBLIC_KEY_CONTENTS_HERE -----END PUBLIC KEY-----`; encryptor.setPublicKey(publicKey); return encryptor.encrypt(plainPassword); }; // Function to send token request const fetchOAuthToken = async (username, plainPassword) => { const encryptedPassword = encryptPassword(plainPassword); const formData = new URLSearchParams(); formData.append('grant_type', 'password'); formData.append('username', username); formData.append('password', encryptedPassword); formData.append('scope', 'openid'); try { const response = await fetch('https://x.x.x.x/oauth2/token', { method: 'POST', headers: { 'Authorization': 'Basic xxxx', // Your client credentials (base64 encoded) 'Content-Type': 'application/x-www-form-urlencoded' }, body: formData }); const data = await response.json(); return data; } catch (error) { console.error('Token request failed:', error); throw error; } };YOUR_PUBLIC_KEY_CONTENTS_HEREwith the actual content from yourwso2-public.pemfile. For production, fetch the public key from a secure backend endpoint instead of hardcoding it.
WSO2 IS doesn't support password decryption out of the box for the password grant flow, so you'll need to build a custom grant handler extension to decrypt the incoming encrypted password before validation.
Steps to implement:
Create a Custom Grant Handler:
Write a Java class that extendsorg.wso2.carbon.identity.oauth2.handlers.grant.AbstractAuthorizationGrantHandlerand overrides theissuemethod to decrypt the password. Here's a sample implementation:package com.yourorg.wso2.extensions; import org.apache.commons.codec.binary.Base64; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.handlers.grant.AbstractAuthorizationGrantHandler; import javax.crypto.Cipher; import java.nio.charset.StandardCharsets; import java.security.PrivateKey; import java.security.KeyFactory; import java.security.spec.PKCS8EncodedKeySpec; public class CustomPasswordGrantHandler extends AbstractAuthorizationGrantHandler { private static final String RSA_ALGORITHM = "RSA"; @Override public boolean issue(OAuth2AccessTokenReqDTO tokenReqDTO) throws IdentityOAuth2Exception { try { // Get encrypted password from request String encryptedPassword = tokenReqDTO.getPassword(); if (encryptedPassword == null || encryptedPassword.isEmpty()) { throw new IdentityOAuth2Exception("Encrypted password is missing"); } // Load private key (store this securely in production—e.g., WSO2 keystore or secure config) String privateKeyStr = "-----BEGIN PRIVATE KEY-----\nYOUR_PRIVATE_KEY_CONTENTS_HERE\n-----END PRIVATE KEY-----"; privateKeyStr = privateKeyStr.replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s", ""); byte[] privateKeyBytes = Base64.decodeBase64(privateKeyStr); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PrivateKey privateKey = keyFactory.generatePrivate(spec); // Decrypt the password Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedBytes = cipher.doFinal(Base64.decodeBase64(encryptedPassword)); String plainPassword = new String(decryptedBytes, StandardCharsets.UTF_8); // Replace encrypted password with plaintext for WSO2's default validation tokenReqDTO.setPassword(plainPassword); // Proceed with normal password grant flow return super.issue(tokenReqDTO); } catch (Exception e) { throw new IdentityOAuth2Exception("Failed to decrypt password", e); } } }Replace
YOUR_PRIVATE_KEY_CONTENTS_HEREwith the content from yourwso2-private.keyfile. For production, avoid hardcoding the private key—use WSO2's keystore or a secure configuration provider instead.Package and Deploy the Extension:
Compile the Java class into a JAR file and copy it to<WSO2_IS_HOME>/repository/components/dropins.Configure WSO2 IS to Use the Custom Handler:
Open<WSO2_IS_HOME>/repository/conf/deployment.tomland add this configuration to replace the default password grant handler:[oauth.grant_type.password] handler = "com.yourorg.wso2.extensions.CustomPasswordGrantHandler"Restart WSO2 IS:
Restart the server to apply all changes.
Use this updated curl command to test (replace ENCRYPTED_PASSWORD with the value generated by your React app's encryption function):
curl --location --request POST 'https://x.x.x.x/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --header 'Authorization: Basic xxxx' \ --data-urlencode 'grant_type=password' \ --data-urlencode 'username=xxxxxxxxx' \ --data-urlencode 'password=ENCRYPTED_PASSWORD' \ --data-urlencode 'scope=openid'
Key Notes:
- Security Best Practices: Never expose the private key to the frontend. Fetch the public key from a secure endpoint instead of hardcoding it.
- Content-Type: Ensure your request uses
application/x-www-form-urlencoded(your original curl usedtext/plain, which isn't correct for form data). - Error Handling: Add robust error handling in both React and the custom grant handler to handle encryption/decryption failures gracefully.
内容的提问来源于stack exchange,提问作者Aman Prakash

