SpringBoot项目中添加证书授权认证

这篇具有很好参考价值的文章主要介绍了SpringBoot项目中添加证书授权认证。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、项目场景

在上线的项目中,需要添加一个定时授权的功能,对系统的进行授权认证,当授权过期时提示用户需要更新授权或获取授权,不让用户无限制的使用软件。


二、方案思路

在查阅相关资料进行整理后,对该场景做了一套解决方案,大致的思路如下:

  • 使用smart-license-1.0.3工具生成校验证书文件(会根据输入的时长和密码进行授权),工具已上传至百度网盘。
链接:https://pan.baidu.com/s/1OXNjw_rgPC3POW5UXTxLcQ?pwd=a0pl 
提取码:a0pl
  • 由于授权证书只允许能够在指定的服务器上使用,所以这里我将授权密码设置为指定服务器的mac地址加上一段自定义的密码,在验证时动态获取软件部署机器的mac地址进行验证(利用mac地址的唯一性)。

  • 由于该证书会自动根据授权时长自动生成结束授权时间,所以为了防止用户修改机器时间去无限使用,所以从数据库任意表读取一个最新时间作为基础时间,然后每次访问操作都去更新和比对这个时间,当发现本次操作比上次操作的时间靠前时,让证书失效。

三、实施流程

1.引入库

        <!-- swagger2 依赖-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>${knife4j.version}</version>
        </dependency>
        
        <!--许可依赖-->
        <!--smart-license 1.0.3授权-->
        <dependency>
            <groupId>org.smartboot.license</groupId>
            <artifactId>license-client</artifactId>
            <version>1.0.3</version>
        </dependency>

2.编写代码

  • 先配置一个系统的缓存,对授权证书文件等其他信息进行缓存
package com.starcone.common.syscenter;


import org.smartboot.license.client.LicenseEntity;

import java.io.File;

/**
 * @Author: Daisen.Z
 * @Date: 2021/7/13 11:41
 * @Version: 1.0
 * @Description: 系统缓存中需要存储的信息
 */
public class SysCacheInfo {

    // 系统加载的证书文件信息
    public static LicenseEntity licenseEntity  = null;

    // 最近一次系统的操作时间
    public static long latOptTimestmp;
}

  • 提供一个证书许可加载的工具类
package com.starcone.common.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.ObjectUtil;
import com.starcone.common.bean.response.ExceptionCast;
import com.starcone.common.bean.response.ResponseResult;
import com.starcone.common.syscenter.SysCacheInfo;
import org.smartboot.license.client.License;
import org.smartboot.license.client.LicenseEntity;
import org.smartboot.license.client.LicenseException;
import org.springframework.util.ResourceUtils;

import java.io.*;
import java.nio.charset.Charset;

/**
 * 许可授权拦截器
 */
public class LicenseUtil {

    // 加载授权文件的方法,该方法必须为单线程
    public synchronized static LicenseEntity loadLocalLEntity(File file) throws Exception {
        // 加载证书,在证书文件过期或无效时该方法会报错
        License license = new License();
        return  license.loadLicense(file);
    }

    public static LicenseCheckResult checkLicenseFile(File file) {
        License license = new License();
        LicenseEntity licenseEntity = null;
        try {
            licenseEntity = license.loadLicense(file);
            String s1 = Md5Util.encodeByMd5(IpUtil.getMACAddress());
            String md5 = licenseEntity.getMd5();
            if (!s1.equals(md5)) {
                // 校验md5值是否相等
                return new LicenseCheckResult(false,"证书文件不匹配");
            }
            return new LicenseCheckResult(true,"");
        } catch (LicenseException e) {
            e.printStackTrace();
            return new LicenseCheckResult(false,"证书文件无效");
        } catch (Exception e) {
            e.printStackTrace();
            return new LicenseCheckResult(false,"证书文件失效");
        }
    }

    // 校验缓存中的licens信息
    public static LicenseCheckResult checkLicense(LicenseEntity licenseEntity) {
        // 授权缓存为空时,先将文件加载至缓存
        if (ObjectUtil.isEmpty(licenseEntity)) {
            return new LicenseCheckResult(false,"未加载证书");
        } else {
            // 校验授权是否被修改
            try {
                String s1 = Md5Util.encodeByMd5(IpUtil.getMACAddress());
                String md5 = licenseEntity.getMd5();
                if (!s1.equals(md5)) {
                    // 校验md5值是否相等
                    return new LicenseCheckResult(false,"证书文件不匹配");
                }
                // 校验授权是否过期
                long expireTime = licenseEntity.getExpireTime(); // 到期时间
                if (System.currentTimeMillis() > expireTime) { // 当前系统时间大于到期时间,说明已经过期
                    return new LicenseCheckResult(false,"证书已过期");
                }
                return new LicenseCheckResult(true,"");
            } catch (LicenseException e) {
                e.printStackTrace();
                return new LicenseCheckResult(false,"证书文件失效");
            } catch (Exception e) {
                e.printStackTrace();
                return new LicenseCheckResult(false,"证书文件失效");
            }
        }
    }

    // 加载授权文件的方法,该方法必须为单线程
    public synchronized static LicenseEntity loadLicenseToCache() throws Exception {
        // 加载证书文件
        ClassPathResource classPathResource = new ClassPathResource("license.txt");
        File file = classPathResource.getFile();
        // 加载证书,在证书文件过期或无效时该方法会报错
        License license = new License();
        SysCacheInfo.licenseEntity = license.loadLicense(file);
        return  SysCacheInfo.licenseEntity;
    }

    public static LicenseCheckResult checkLocalLicenseFile() {
        // 校验文件是否有效
        ClassPathResource classPathResource = new ClassPathResource("license.txt");
        File file = null;
        try {
            file = classPathResource.getFile();
            String absolutePath = ResourceUtils.getFile("classpath:license.txt").getAbsolutePath();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return checkLicenseFile(file);
    }


    // 校验缓存中的licens信息
    public static LicenseCheckResult checkLocalLicenseCache() {
        return checkLicense(SysCacheInfo.licenseEntity);
    }

    public static class LicenseCheckResult{
        private boolean checkResult;
        private String msg;

        public LicenseCheckResult(boolean checkResult, String msg) {
            this.checkResult = checkResult;
            this.msg = msg;
        }

        public LicenseCheckResult() {
        }

        public boolean getCheckResult() {
            return checkResult;
        }

        public void setCheckResult(boolean checkResult) {
            this.checkResult = checkResult;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }
    }

    // 更新本地文件
    public static void updateLocalLicense(File file) throws IOException {
        BufferedInputStream inputStream = FileUtil.getInputStream(file);
        InputStreamReader streamReader = new InputStreamReader(inputStream);
        BufferedReader reader = new BufferedReader(streamReader);
        String line;
        StringBuilder stringBuilder = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
        }
        reader.close();

        ClassPathResource classPathResource = new ClassPathResource("license.txt");
        File file1 = null;
        try {
            file1 = classPathResource.getFile();
            String absolutePath = ResourceUtils.getFile("classpath:license.txt").getAbsolutePath();
            FileUtil.writeString(String.valueOf(stringBuilder),file1, Charset.forName("UTF-8"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

  • 前后端交互的Controller类
package com.starcone.web.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import com.starcone.common.bean.response.ExceptionCast;
import com.starcone.common.bean.response.ResponseResult;
import com.starcone.common.syscenter.SysCacheInfo;
import com.starcone.common.util.IpUtil;
import com.starcone.common.util.LicenseUtil;
import com.starcone.common.util.LogHelper;
import com.starcone.common.util.Md5Util;
import com.starcone.service.SysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.smartboot.license.client.License;
import org.smartboot.license.client.LicenseEntity;
import org.smartboot.license.client.LicenseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.UUID;

/**
 * @Author: Daisen.Z
 * @Date: 2024/1/17 15:15
 * @Version: 1.0
 * @Description:
 */
@RestController
@RequestMapping("/licensManager")
@Api(value = "LicensController", tags = {"授权管理接口"})
public class LicensManagerController {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private LogHelper logHelper;

    @GetMapping("/getEuqMac")
    public ResponseResult addDemo() throws Exception {
        ;return ResponseResult.success(IpUtil.getMACAddress());
    }

    // http://localhost:8080/track/licensManager/reloadLicens
    @ApiOperation(value = "重新加载Licens和校准时钟", notes = "授权管理接口", produces = "application/json")
    @GetMapping("/reloadLicens")
    public ResponseResult reloadLicens() throws Exception {
        // 校准一下时钟信息
        SysCacheInfo.latOptTimestmp = System.currentTimeMillis();
        LicenseUtil.loadLicenseToCache();
        ;return ResponseResult.success("过期时间"+ DateUtil.format(new Date(SysCacheInfo.licenseEntity.getExpireTime()),"yyyy-MM-dd HH:mm:ss"));
    }



    /**
     * 基站信息上传
     * @return
     * @throws IOException
     */
    @PostMapping("/uploadLicens")
    public ResponseResult upload(MultipartFile file){
        File file1 = FileUtil.createTempFile(new File(""));
        try {
            file.transferTo(file1);
        } catch (IOException e) {
            logHelper.failLog("更新授权","文件上传异常,"+file.getOriginalFilename());
            return ResponseResult.error(503,e.getMessage());
        }
        LicenseUtil.LicenseCheckResult licenseCheckResult = LicenseUtil.checkLicenseFile(file1);
        if (!licenseCheckResult.getCheckResult()){ // 如果证书无效
            logHelper.failLog("更新授权","证书无效");
            return ResponseResult.error(503,licenseCheckResult.getMsg());
        }

        // 校验通过后更新本地文件
        try {
            LicenseUtil.updateLocalLicense(file1);
        } catch (IOException e) {
            logHelper.failLog("更新授权","本地授权文件更新异常"+file.getOriginalFilename());
            return ResponseResult.error(503,"文件更新异常");
        }
        // 加载授权文件至本地缓存
        try {
            LicenseUtil.loadLicenseToCache();
        } catch (Exception e) {
            logHelper.failLog("更新授权","本地授权文件加载异常"+file.getOriginalFilename());
            return ResponseResult.error(503,"加载本地文件异常");
        }
        logHelper.successdLog("更新授权","更新成功"+file.getOriginalFilename()+",授权截至日期"+ DateUtil.format(new Date(SysCacheInfo.licenseEntity.getExpireTime()),"yyyy-MM-dd HH:mm:ss"));
        if (FileUtil.isNotEmpty(file1)){
            FileUtil.del(file1);
        }
        return ResponseResult.success();
    }

}

  • 提供一个可以获取软件部署的服务器mac地址的接口(工具类)
package com.starcone.common.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;

/**
 * IP地址相关工具类
 */
public class IpUtil {

    private static final Log logger = LogFactory.getLog(IpUtil.class);

    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        logger.error(e.getMessage(), e);
                    }
                    ipAddress = inet.getHostAddress();
                }
            }
            // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress = "";
        }

        return ipAddress;
    }


    // 获取MAC地址的方法
    public static String getMACAddress() throws Exception {
        // 获得网络接口对象(即网卡),并得到mac地址,mac地址存在于一个byte数组中。
        InetAddress ia = InetAddress.getLocalHost();
        byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
        // 下面代码是把mac地址拼装成String
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append("-");
            }
            // mac[i] & 0xFF 是为了把byte转化为正整数
            String s = Integer.toHexString(mac[i] & 0xFF);
            // System.out.println("--------------");
            // System.err.println(s);
            sb.append(s.length() == 1 ? 0 + s : s);
        }
        // 把字符串所有小写字母改为大写成为正规的mac地址并返回
        return sb.toString().toUpperCase();
    }
}

  • 根据mac地址生成证书文件
    SpringBoot项目中添加证书授权认证,系统框架,spring boot,java,spring
    输入授权时间,校验密码(主机mac加上自定义密码)
    SpringBoot项目中添加证书授权认证,系统框架,spring boot,java,spring
    生成的授权文件
    SpringBoot项目中添加证书授权认证,系统框架,spring boot,java,spring

  • 将证书文件放到项目的resource目录
    SpringBoot项目中添加证书授权认证,系统框架,spring boot,java,spring

  • 编写启动类,在项目启动时加载证书信息,并读取数据库最新的时间作为基础时间,防止修改系统时间和文件篡改

package com.starcone.common.task;

import cn.hutool.core.util.ObjectUtil;
import com.starcone.common.bean.response.ExceptionCast;
import com.starcone.common.syscenter.SysCacheInfo;
import com.starcone.common.util.LicenseUtil;
import com.starcone.domain.SysLog;
import com.starcone.service.SysLogService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;

/**
 * @Author: Daisen.Z
 * @Date: 2021/7/13 9:55
 * @Version: 1.0
 * @Description: 系统启动时要执行的任务
 */
@Component
public class SysStartTask {


    private Logger logger = LogManager.getLogger();

    @Autowired
    private SysLogService sysLogService;

    @PostConstruct
    public void init() {
        logger.info("****************执行系统启动初始化****************");
        // 加载认证证书文件信息
        if (SysCacheInfo.licenseEntity == null){
            try {
                LicenseUtil.loadLicenseToCache();
            } catch (Exception e) {
                ExceptionCast.cast("License load to Cache Exception");
            }
        }


        // 从数据库读取一个最新的时间到缓存中
        SysLog sysLog = sysLogService.queryOneByMaxTime();
        if (ObjectUtil.isEmpty(sysLog)){
            SysCacheInfo.latOptTimestmp = System.currentTimeMillis();
        }else {
            Date addTime = sysLog.getAddTime();
            SysCacheInfo.latOptTimestmp = addTime.getTime();
        }
    }


}

  • 编写拦截器,在访问系统接口时,进行证书校验,并校验系统时间是否被修改
    拦截器:
package com.starcone.common.config.auth;

import com.starcone.common.syscenter.SysCacheInfo;
import com.starcone.common.util.LicenseUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author: Daisen.Z
 * @Date: 2024/1/17 18:57
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class JarAuthInterceptor implements HandlerInterceptor {

    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String uri = request.getRequestURI();
        if (uri.endsWith("login") || uri.endsWith("licens")) {
            return true;
        }
        // 校验证书文件
        boolean checkResult = LicenseUtil.checkLocalLicenseCache().getCheckResult();
        long timeMillis = System.currentTimeMillis();
        boolean timeFlag =  ( timeMillis+ 180000) > SysCacheInfo.latOptTimestmp;
        if (checkResult && timeFlag){ // 操作时间不能比最近上一次操作系统的时间小超过3分钟
            // 更新最近一次操作的时间
            SysCacheInfo.latOptTimestmp = System.currentTimeMillis();
            return true;
        } else {
            if (!timeFlag) {// 跳转到请不要修改服务器时钟的页面
                if ("XMLHttpRequest".equals (request.getHeader ("X-Requested-With"))) { // ajax跳转
                        //告诉ajax我是重定向
                    response.setHeader ("REDIRECT", "REDIRECT");
                    //告诉ajax我重定向的路径
                    response.setHeader ("CONTENTPATH", "/licensDate");
                    response.setStatus (HttpServletResponse.SC_FORBIDDEN);
                } else {
                    // 如果不是ajax请求,直接跳转
                    response.sendRedirect (request.getContextPath ( ) + "/licensDate");
                }
            }else {
                if ("XMLHttpRequest".equals (request.getHeader ("X-Requested-With"))) {// ajax跳转
                    //告诉ajax我是重定向
                    response.setHeader ("REDIRECT", "REDIRECT");
                    //告诉ajax我重定向的路径
                    response.setHeader ("CONTENTPATH", "/licens");
                    response.setStatus (HttpServletResponse.SC_FORBIDDEN);
                } else {
                    response.sendRedirect (request.getContextPath ( ) + "/licens");
                }
            }
            return false;
        }
    }
}

配置拦截器生效:

package com.starcone.common.config;

import com.starcone.common.config.auth.JarAuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Daisen.Z
 * @Date: 2024/1/17 18:58
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class SignAuthConfiguration implements WebMvcConfigurer {
    @Autowired
    public JarAuthInterceptor jarAuthInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        //注册TestInterceptor拦截器
        InterceptorRegistration registration = registry.addInterceptor(jarAuthInterceptor);
        registration.addPathPatterns("/**");                      //所有路径都被拦截
        List<String> excludePath = new ArrayList<>();
        excludePath.add("/login");
        excludePath.add("/licens");
        excludePath.add("/licensDate");
        excludePath.add("/licensManager/**");
        excludePath.add("/dologin");
        excludePath.add("/libs/**");
        excludePath.add("/static/**");
        excludePath.add("/src/**");
        excludePath.add("/js/**");
        excludePath.add("/icon/**");
        // 许可授权拦截器
        registration.excludePathPatterns(excludePath);
    }
}

四、拓展

可以根据项目需求进行适当修改,开搞吧!文章来源地址https://www.toymoban.com/news/detail-809148.html

到了这里,关于SpringBoot项目中添加证书授权认证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot 如何使用 OAuth2 进行认证和授权

    OAuth2 是一种授权框架,可以用于实现第三方应用程序访问用户资源的安全性。在 SpringBoot 中,我们可以使用 Spring Security 和 Spring OAuth2 来实现 OAuth2 的认证和授权功能。本文将介绍如何在 SpringBoot 中使用 OAuth2 进行认证和授权。 在开始介绍如何使用 OAuth2 进行认证和授权之前,

    2024年02月13日
    浏览(35)
  • Springboot +spring security,自定义认证和授权异常处理器

    在Spring Security中异常分为两种: AuthenticationException 认证异常 AccessDeniedException 权限异常 我们先给大家演示下如何自定义异常处理器,然后再结合源码帮助大家进行分析 如何创建一个SpringSecurity项目,前面文章已经有说明了,这里就不重复写了。 3.1配置SecurityConfig 这里主要是

    2024年02月07日
    浏览(43)
  • SpringBoot集成SpringSecurity从0到1搭建权限管理详细过程(认证+授权)

    最近工作需要给一个老系统搭建一套权限管理,选用的安全框架是SpringSecurity,基本上是结合业务从0到1搭建了一套权限管理,然后想着可以将一些核心逻辑抽取出来写一个权限通用Demo,特此记录下。 Spring Security是 Spring家族中的一个安全管理框架。相比与另外一个安全框架

    2024年02月04日
    浏览(43)
  • SSM+Shiro安全框架整合(完成安全认证--登录+权限授权)+ssm整合shiro前后端分离

    目录 1.搭建SSM框架  1.1.引入相关的依赖 1.2. spring配置文件 1.3. web.xml配置文件 1.4.配置Tomcat并启动 2.ssm整合shiro---认证功能  (1).引入依赖 (2).修改spring配置文件 (3).修改web.xml文件 (4).新建login.jsp(登录页面) (5).新建success.jsp(登录成功后跳转到此) (6).创建User实体类 (7).创建LoginVo

    2024年02月15日
    浏览(46)
  • springboot添加SSL证书,支持https与http

    将证书文件放在/resource目录下 修改配置文件

    2024年02月10日
    浏览(43)
  • 项目管理认证 | 什么是PMP项目管理?PMP证书有什么用?

    项目管理?听起来似乎离我们很遥远。其实不然, 学习了项目管理知识后,你会发现, “一切都是项目,一切也将成为项目” 。 你可以把港珠澳大桥的建设、开发一款新型手机、开发一个好用的CRM系统、推广一款新研发的医疗器械定义为一个项目,你也可以把你们家的房屋

    2024年01月23日
    浏览(55)
  • 【开源】SpringBoot框架开发企业项目合同信息系统

    基于JAVA+Vue+SpringBoot+MySQL的企业项目合同信息系统,包含了合同审批模块、合同签订模块、合同预定模块和合同数据可视化模块,还包含系统自带的用户管理、部门管理、角色管理、菜单管理、日志管理、数据字典管理、文件管理、图表展示等基础模块,企业项目合同信息系统

    2024年02月20日
    浏览(49)
  • SpringBoot整合自签名SSL证书,转变HTTPS安全访问(单向认证服务端)

    HTTP 具有相当优秀和方便的一面,然而 HTTP 并非只有好的一面,事物皆具两面性,它也是有不足之处的。例如: 通信使用明文(不加密),内容可能会被窃听。 不验证通信方的身份,因此有可能会遭遇伪装。 无法证明报文的完整性,所以有可能会遭篡改等。 因HTTP有存在通信

    2024年02月06日
    浏览(64)
  • SpringBoot小项目——简单的小区物业后台管理系统 & 认证鉴权 用户-角色模型 & AOP切面日志 & 全局异常【源码】

    基于SpringBoot的简单的小区物业后台管理系统,主要功能有报修的处理,楼宇信息和房屋信息的管理,业主信息的管理【核心】,以及数据统计分析模块Echarts绘图;此外采用用户-角色权限模型,结合自定义注解实现简单的权限管理功能,采用aop切面实现日志的存储,全局异常

    2024年02月06日
    浏览(52)
  • 【SpringBoot】自从集成spring-security-oauth2后,实现统一认证授权so easy!

    principal:能唯一标识用户身份的属性,一个用户可以有多个principal 如登录的唯一标识, 用户可以使用用户名或手机或邮箱进行登录 ,这些principal是让别人知道的 credential:凭证,用户才知道的,简单的说就是 密码 如:手机开锁,可以使用 屏幕密码 也可以使用 人脸识别 ,

    2023年04月24日
    浏览(116)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包