基于ldap实现登录认证

        最近开发的应用需要外协人员实现登录认证,外协人员的密码等信息已经录入到ldap, 需要连接ldap进行登录认证。下面先介绍一下登录的网络旅程图。

一.nginx实现AES加密

nginx请求处理入口(前端请求为json格式)

 location /aes {default_type text/html;content_by_lua_block{local access_filter = require 'resty.aes_auth'local r = access_filter.aes_auth()ngx.header.content_type = "application/json; charset=UTF-8"if r == true then ngx.say([[{"code":200,"message":"Certification         successful!","data":true,"logCode":null}]])else ngx.say([[{"code":401,"message":"Authentication failed!","data":false,"logCode":null }]])endngx.exit(200)}}

 openresty请求认证接口脚本

local aes = require "resty.aes"
local cjson = require("cjson.safe")
local http = require("resty.http")
local key = "abcdefmJTNn}8Z#2`"
local iv = "1234567890123456"local _M = {}
function _M.aes_auth()ngx.req.read_body()local args,err = ngx.req.get_body_data()if (not args) or (err) thenreturn falseendlocal arg_json = cjson.decode(args)local username = arg_json.usernamelocal password = arg_json.passwordif (not username) or (not password) thenreturn falseendlocal cript = aes:new(key, nil, aes.cipher(128, "cbc"), {iv=iv, method=nil})local pwd = cript:encrypt(password)if pwd thenpwd = ngx.encode_base64(pwd)elsereturn falseendlocal httpc = http.new()local requestBody = {username = username,password = pwd}local json_body = cjson.encode(requestBody)local resp,err = httpc:request_uri("http://10.1.1.1:8080", {method = "POST",path = "/ldap/authUser",body = json_body,headers = {  ---header参数["Content-Type"] = "application/json;charset=UTF-8"}})if err thenreturn falseendlocal result = falseif resp thenlocal data = cjson.decode(resp.body).dataif data thenresult = dataendendreturn result
endreturn _M

 二.应用服务调用ldap服务

引入依赖

<!--ldap-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-ldap</artifactId><version>2.3.12.RELEASE</version>
</dependency>
<!--aes对称加密-->
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.56</version>
</dependency>

AES加密解密工具类,需要注意的是nginx不支持PKCS5Padding填充方式。

package com.xxx.xxx.xxx.util;import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Base64;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import lombok.extern.slf4j.Slf4j;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.util.Base64Utils;/*** description:AES对称加密工具类** @author: lgq* @create: 2024-01-26 10:03*/
@Slf4j
public class AESUtil {/*** 日志相关*//*** 编码*/private static final String ENCODING = "UTF-8";/*** 算法定义*/private static final String AES_ALGORITHM = "AES";/*** 指定填充方式*/private static final String CIPHER_PADDING = "AES/ECB/PKCS5Padding";//必须使用PKCS7Padding,因为nginx不支持PKCS5Padding填充方式private static final String CIPHER_CBC_PADDING = "AES/CBC/PKCS7Padding";/*** 偏移量(CBC中使用,增强加密算法强度)*/private static final String IV_SEED = "1234567890123456";private static final String RANDOM_SECRET = "abcefmJTNn}8Z#2`";static {// 指定使用bouncycastle包来加密, 引入目的就是为了支持AES/CBC/PKCS7PaddingSecurity.addProvider(new BouncyCastleProvider());}public static String getRandomSecret() {return RANDOM_SECRET;}/*** AES加密** @param content 待加密内容* @param aesKey  密码* @return*/public static String encrypt(String content, String aesKey) {if (StringUtils.isBlank(content)) {log.info("AES encrypt: the content is null!");return null;}//判断秘钥是否为16位if (StringUtils.isNotBlank(aesKey) && aesKey.length() == 16) {try {//对密码进行编码byte[] bytes = aesKey.getBytes(ENCODING);//设置加密算法,生成秘钥SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);// "算法/模式/补码方式"Cipher cipher = Cipher.getInstance(CIPHER_PADDING);//选择加密cipher.init(Cipher.ENCRYPT_MODE, skeySpec);//根据待加密内容生成字节数组byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING));//返回base64字符串return Base64Utils.encodeToString(encrypted);} catch (Exception e) {log.info("AES encrypt exception:" + e.getMessage());throw new RuntimeException(e);}} else {log.info("AES encrypt: the aesKey is null or error!");return null;}}/*** 解密** @param content 待解密内容* @param aesKey  密码* @return*/public static String decrypt(String content, String aesKey) {if (StringUtils.isBlank(content)) {log.info("AES decrypt: the content is null!");return null;}//判断秘钥是否为16位if (StringUtils.isNotBlank(aesKey) && aesKey.length() == 16) {try {//对密码进行编码byte[] bytes = aesKey.getBytes(ENCODING);//设置解密算法,生成秘钥SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);// "算法/模式/补码方式"Cipher cipher = Cipher.getInstance(CIPHER_PADDING);//选择解密cipher.init(Cipher.DECRYPT_MODE, skeySpec);//先进行Base64解码byte[] decodeBase64 = Base64Utils.decodeFromString(content);//根据待解密内容进行解密byte[] decrypted = cipher.doFinal(decodeBase64);//将字节数组转成字符串return new String(decrypted, ENCODING);} catch (Exception e) {log.info("AES decrypt exception:" + e.getMessage());throw new RuntimeException(e);}} else {log.info("AES decrypt: the aesKey is null or error!");return null;}}/*** AES_CBC加密** @param content 待加密内容* @param aesKey  密码* @return*/public static String encryptCBC(String content, String aesKey) {if (StringUtils.isBlank(content)) {log.info("AES_CBC encrypt: the content is null!");return null;}//判断秘钥是否为16位if (StringUtils.isNotBlank(aesKey) && aesKey.length() == 16) {try {//对密码进行编码byte[] bytes = aesKey.getBytes(ENCODING);//设置加密算法,生成秘钥SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);// "算法/模式/补码方式"Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING);//偏移IvParameterSpec iv = new IvParameterSpec(IV_SEED.getBytes(ENCODING));//选择加密cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);//, iv//根据待加密内容生成字节数组byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING));//返回base64字符串return Base64Utils.encodeToString(encrypted);} catch (Exception e) {log.info("AES_CBC encrypt exception:" + e.getMessage());throw new RuntimeException(e);}} else {log.info("AES_CBC encrypt: the aesKey is null or error!");return null;}}/*** AES_CBC解密** @param content 待解密内容* @param aesKey  密码* @return*/public static String decryptCBC(String content, String aesKey) {if (StringUtils.isBlank(content)) {log.info("AES_CBC decrypt: the content is null!");return null;}//判断秘钥是否为16位if (StringUtils.isNotBlank(aesKey) && aesKey.length() == 16) {try {//对密码进行编码byte[] bytes = aesKey.getBytes(ENCODING);//设置解密算法,生成秘钥SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);//偏移IvParameterSpec iv = new IvParameterSpec(IV_SEED.getBytes(ENCODING));// "算法/模式/补码方式"Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING);//选择解密cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);//先进行Base64解码byte[] decodeBase64 = Base64Utils.decodeFromString(content);//根据待解密内容进行解密byte[] decrypted = cipher.doFinal(decodeBase64);//将字节数组转成字符串return new String(decrypted, ENCODING);} catch (Exception e) {log.info("AES_CBC decrypt exception:" + e.getMessage());throw new RuntimeException(e);}} else {log.info("AES_CBC decrypt: the aesKey is null or error!");return null;}}}

ladp配置类

package com.xxx.xxx.xxx.config;import javax.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;/*** description:LdapConfig** @author: lgq* @create: 2024-01-25 10:34*/
@Configuration
public class LdapConfig {@Resourceprivate LdapProperties ldapProperties;@Beanpublic LdapTemplate ldapTemplate() {LdapContextSource contextSource = new LdapContextSource();contextSource.setUrl(ldapProperties.getUrls());contextSource.setBase(ldapProperties.getBase());contextSource.setUserDn(ldapProperties.getUsername());contextSource.setPassword(ldapProperties.getPassword());contextSource.afterPropertiesSet();LdapTemplate ldapTemplate = new LdapTemplate(contextSource);ldapTemplate.setIgnorePartialResultException(true);ldapTemplate.setDefaultTimeLimit(1000);ldapTemplate.setDefaultCountLimit(100);return ldapTemplate;}}package com.xxx.xxx.xxx.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;/*** description:ldapProperties** @author: lgq* @create: 2024-01-25 18:13*/
@Data
@ConfigurationProperties(prefix = "spring.ldap")
public class LdapProperties {/*** ldap服务地址*/private String urls;/*** 用户账号*/private String username;/*** 密码*/private String password;/*** base路径*/private String base;
}yml文件配置:spring:profiles: prodapplication:name: service-xxxldap:urls: "ldap://10.1.1.1:389"password: "xxxxxxxx"username: "cn=xxx.LDAP,ou=xxx,ou=xxx,dc=xxx,dc=xxx"base: "dc=xxx,dc=xxx"

认证服务类

package com.xxx.xxx.xxx.service.impl;import java.nio.charset.StandardCharsets;
import java.util.Base64;import javax.annotation.Resource;import com.xxx.xxx.xxx.service.LdapService;
import com.xxx.xxx.xxx.util.AESUtil;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.stereotype.Service;/*** description:LdapServiceImpl** @author: lgq* @create: 2024-01-26 09:26*/
@Service
@Slf4j
public class LdapServiceImpl implements LdapService {@Resourceprivate LdapTemplate ldapTemplate;/*** 验证登录用户的账号密码是否正确* @param username* @param password* @return*/@Overridepublic boolean authLoginUser(String username, String password) {if (ObjectUtils.isEmpty(username) || ObjectUtils.isEmpty(password)) {return false;}/*** aes对password进行解密*/String content = AESUtil.decryptCBC(password, AESUtil.getRandomSecret());if (ObjectUtils.isEmpty(content)) {return false;}String baseDn = "";String filter = "sAMAccountName=" + username;boolean result = false;try {result = ldapTemplate.authenticate(baseDn, filter, content);} catch (Exception ex) {log.error(ex.getMessage(), ex);} catch (Error er) {log.error(er.getMessage(), er);}return result;}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/439740.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

this.$store undefined

报错&#xff1a;vuex报错 this.$store显示undefined&#xff0c;可能存在的问题&#xff0c;从以下几个方向排查 1、查看store文件中的vuex实例对象是否暴漏 2、main.js中是否注入store 3、如果上边均没问题&#xff0c;打开package.json&#xff0c;查看vue与vuex的版本&am…

系列五十、idea父子项目忽略部分文件

一、idea父子项目忽略部分文件 **/mvnw **/mvnw.cmd **/.mvn **/target/ .idea **/.gitignore

电商API接口的应用|电商跨境电商商品采集高效解决方案

电商API接口的应用|电商跨境电商商品采集高效解决方案 面对数十万亿元的跨境电商市场&#xff0c;以阿里巴巴国际站为代表的跨境电商数字平台&#xff0c;在政策、需求以及供应链的驱动下&#xff0c;为中小企业提供了全产业链、全供应链一体化综合服务&#xff0c;让越来越多…

Ansys Lumerical | 闪耀光栅

附件下载 联系工作人员获取附件 此示例说明如何计算闪耀光栅的光栅阶数。该光栅在每个波长处都有许多光栅阶数。为了捕获全反射和透射的特征&#xff0c;监视器中需要更多的频率点。 模拟设置 上面的仿真文件中显示了闪耀光栅。它由低折射率 &#xff08;1.4&#xff09; 基…

红黑树封装实现STL-map、set

利用红黑树作为模板封装的思路 将红黑树作为一个基础的类模板&#xff0c;通过给这个类模板传递不同的参数&#xff0c;从而控制它所实现的容器。 最主要的点是用自己的map和set通过传递不同的模板参数控制红黑树第二个模板参数 T 来确定传入的到底是 Key 还是 pair<Key, …

Java异常处理集合

Java异常处理 Java语言在执行后会中断&#xff0c;也就是在出错位置后的代码都不会被执行&#xff0c;为了使非致命错误后的程序仍然能够执行&#xff0c;引入异常处理机制。 异常 可处理的异常用Exception表示&#xff0c;不可处理的异常用Error表示&#xff0c;通常是栈内…

探索数字经济:从基础到前沿的奇妙旅程

新一轮技术革命方兴未艾&#xff0c;特别是以人工智能、大数据、物联网等为代表的数字技术革命&#xff0c;催生了一系列新技术、新产业、新模式&#xff0c;深刻改变着世界经济面貌。数字经济已成为重组全球要素资源、重塑全球经济结构、改变全球竞争格局的关键力量。预估到20…

儿童写字用什么台灯比较好?学生专用台灯第一品牌

现在孩子的生活比我们小学时候更加丰富多彩&#xff0c;当然也更“忙”了起来&#xff01;正是因为上学之后&#xff0c;有了这么多的学习任务&#xff0c;所以孩子的桌面空间使用频率越来越高&#xff01;为了让孩子更好地完成学习任务&#xff0c;以及保护视力。越来越多家长…

BUUCTF misc 二维码

目录 将Windows中的文件传输到Linux虚拟机中 binwalk用法 kali-linux中使用fcrackzip工具爆破zip密码 打开题目&#xff1a; 下载并解压后&#xff0c;得到一张二维码图片&#xff0c;我们使用 toolhelper.cn 里的二维码解析小工具查看得到&#xff1a; 可以看到 secret is …

led护眼灯真的能护眼吗安全吗?护眼又安全的LED灯推荐

近些年来&#xff0c;中国患近视的孩子越来越多&#xff0c;为了让孩子在家写作业时眼睛少受损伤&#xff0c;很多家长专门准备了LED台灯。但不合格LED灯反而加剧孩子们视力疲劳&#xff0c;甚至出现近视。其中重要一个原因是某些LED灯存在着严重的频闪&#xff0c;长期在这样的…

关于bypassuac的探究——基础知识

用户帐户控制(User Account Control)是Windows Vista&#xff08;及更高版本操作系统&#xff09;中一组新的基础结构技术&#xff0c;可以帮助阻止恶意程序&#xff08;有时也称为“恶意软件”&#xff09;损坏系统&#xff0c;同时也可以帮助组织部署更易于管理的平台。 使用…

java8 Duration类学习

Duration类 官网地址 基于时间的时间量&#xff0c;例如“34.5秒”。 此类以秒和纳秒为单位对时间的量或量进行建模。它可以使用其他基于持续时间的单位访问&#xff0c;如分钟和小时。此外&#xff0c;可以使用DAYS单位&#xff0c;并将其视为完全等于24小时&#xff0c;从…