shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。

简介: 这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。

前言

一、逻辑

1. 登录逻辑

shiro 做安全权限控制。那么shiro的过滤器和数据源的处理主要是针对token的认证和授权。
而用户的密码验证则还是在service层中进行处理。

  1. 首先将用户登录的接口 /user/login 在shiro过滤器中放开,不在拦截,设置为 anon
  2. 发送post请求携带用户名和密码,进行登录。走这个请求时,在上一步已经被设置了白名单。走控制器,业务层service,在这里进行判断,用户名密码判断无误后,设置token和id,然后返回到前端。
  3. 总结一下:用户的密码登录和shiro是无关的,正常的判断即可。注意的是需要返回的数据,这里仅有id和token。token也是UUID生成的,并存在redis中。
  4. 访问其他接口时,拿着token放在请求头中,然后发请求,没有被shiro设置在白名单里的请求会被shiro拦截,拦截流程如下:
    ShiroAccessControlFilter类:isAccessAllowed():onAccessDenied(),用到了ShiroUsernamePasswordToken
    ->ShiroRealm类:doGetAuthenticationInfo方法
    ->ShiroHashedCredentialsMatcher类:doCredentialsMatch()
  5. 根据博客三,这里重写的doCredentialsMatch()方法就是 shiro的过滤器的最后一步,也是至关重要的一步。
    6. 接下来就可以去控制的接口了,如果遇到@RequiresPermissions() 注解,再去ShiroRealm类中doGetAuthorizationInfo()授权方法去授予权限即可,再去接口即可。

2. 项目目录结构

在这里插入图片描述

3. 开发逻辑

a. redis 开发工具类

redis的配置类和工具类,我就不再贴出,本博客主要写shiro的代码,代码可去GitHub上拉取下来观看

  1. config包下的RedisConfig配置类
  2. serializer包下的MyStringRedisSerializer序列化类
  3. utils包下的RedisUtil类

代码不再贴了,都在GitHub上

b. 密码加密工具类

  1. utils 包下的 PasswordUtils 工具类。
  2. PasswordEncoder密码编码类。

代码不再贴了,都在GitHub上

c. swagger配置

  1. config包下的 SwaggerConfig配置类
  2. 配置类上的启动注解 @EnableSwagger2

代码不再贴了,都在GitHub上

d. shiro开发 流程

  1. 先开发 ShiroConfig,设置自定义过滤器 ShiroAccessControlFilter,并设置过滤器的白名单
    对登录的请求设置为 anon。
  2. 开发 ShiroAccessControlFilter拦截器,这里是对 token 的简单过滤验证,并进行主体提交,提交到自定义数据域 realm。
    开发拦截器中,还要开发ShiroUsernamePasswordToken,自己实现shiro认证机制,就要重写类 UsernamePasswordToken
  3. 开发自定义realm:ShiroRealm类。数据域部分,进行授权和认证。
    认证:对token进行过滤,用户名密码登录部分还是在业务层处理
    授权:从数据库中获取,设计到表 role、permission、user_role、role_permission 四个表
  4. 开发 token 的最后过滤处理 ShiroHashedCredentialsMatcher,继承 HashedCredentialsMatcher类实现方法doCredentialsMatch()

以上四步其实就是 shiro 开发的全部,基本上都是配置式的代码。

二、shiro代码开发

1. shiroConfig.java

package com.feng.config;

import com.feng.shiro.ShiroAccessControlFilter;
import com.feng.shiro.ShiroHashedCredentialsMatcher;
import com.feng.shiro.ShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    /**
     * token 的过滤
     * 自定义token 校验
     * 学习说明:其实 下面的 ShiroHashedCredentialsMatcher(自定义的) 也继承了 HashedCredentialsMatcher。
     * 需要在 CustomRealm bean 中进行设置
     * @return
     */
    @Bean(name = "shiroHashedCredentialsMatcher")
    public ShiroHashedCredentialsMatcher shiroHashedCredentialsMatcher() {
        return new ShiroHashedCredentialsMatcher();
    }

    /**
     * 登录的 认证域
     *
     * @param hashedCredentialsMatcher
     * @return
     */
    @Bean(name = "shiroRealm")
    public ShiroRealm getShiroRealm(@Qualifier("shiroHashedCredentialsMatcher") HashedCredentialsMatcher hashedCredentialsMatcher) {
        ShiroRealm shiroRealm = new ShiroRealm();
        // 自定义 处理 token 过滤
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return shiroRealm;
    }

    /**
     * shiro 的安全管理器
     *
     * @param shiroRealm
     * @return
     */
    @Bean(name = "securityManager")
    public SecurityManager securityManager(@Qualifier("shiroRealm") ShiroRealm shiroRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm);
        return securityManager;
    }
    /**
     * shiro 的过滤器
     * 需要了解 shiro 的权限关键字含义:
     *  anon,表示不拦截的路径
     *  authc,表示拦截的路径
     *
     *  匹配时,首先匹配 anon 的,然后最后匹配 authc
     *
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /*
         * 自定义过滤器
         * */
        //自定义拦截器限制并发人数,参考博客:
        LinkedHashMap<String, Filter> filtersMap = new LinkedHashMap<>();
        //用来校验token
        filtersMap.put("token", new ShiroAccessControlFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
        /*
         * 以下为权限控制
         * */
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/user/login", "anon");
//        filterChainDefinitionMap.put("/user/test", "anon");

        // 拦截所有
        filterChainDefinitionMap.put("/**", "token,authc");

        // 没有登录的用户请求需要登录的页面时自动跳转到登录页面。 配置 shiro 默认登录界面地址,
        shiroFilterFactoryBean.setLoginUrl("/api/user/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 下面两个配置类 AuthorizationAttributeSourceAdvisor 和 DefaultAdvisorAutoProxyCreator,开启 shiro aop 注解 支持.
     * 使用代理方式;所以需要开启代码支持;
     * <p>
     * 如果不加 使用 @RequirePermissions 无效
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
}

2. ShiroAccessControlFilter

package com.feng.shiro;

import com.alibaba.fastjson.JSON;
import com.feng.constant.Constant;
import com.feng.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: CustomAccessControlerFilter
 * @Description: 自定义的 token 过滤器。
 * @createTime:
 * @Author: 冯凡利
 * @UpdateUser: 冯凡利
 * @Version: 0.0.1
 */

/**
 * 这里的异常,全局异常无法处理,比较高级没有到达 方法,所以需要自己处理  try-catch
 */
@Slf4j
public class ShiroAccessControlFilter extends AccessControlFilter {
    /**
     * 是否 允许 访问下一层
     * true: 允许,交下一个Filter 处理
     * false: 交给自己处理,往下执行 onAccessDenied 方法
     * @param servletRequest
     * @param servletResponse
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        return false;
    }

    /**
     * 表示访问拒绝时是否自己处理,
     * 如果返回 true 表示自己不处理且 继续拦截器执行,往下执行
     * 返回 false 表示自己已经处理了(比如重定向到另一个界面)处理完毕。
     *
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        HttpServletRequest request= (HttpServletRequest) servletRequest;
        try {
            log.info("接口请求方式{}",request.getMethod());
            log.info("接口请求地址",request.getRequestURI());
            String token=request.getHeader(Constant.TOKEN_SESSION_ID);
            if(StringUtils.isEmpty(token)){
                throw new BusinessException(4010001,"用户凭证已失效请重新登录认证");
            }
            ShiroUsernamePasswordToken customUsernamePasswordToken=new ShiroUsernamePasswordToken(token);
            getSubject(servletRequest,servletResponse).login(customUsernamePasswordToken);
        } catch (BusinessException e) {
            customResponse(e.getMessageCode(),e.getMessage(),servletResponse);
            return false;
        } catch (AuthenticationException e) {
            if(e.getCause() instanceof BusinessException){
                BusinessException businessException= (BusinessException) e.getCause();
                customResponse(businessException.getMessageCode(),businessException.getMessage(),servletResponse);
            }else {
                customResponse(4000001,"用户认证失败",servletResponse);
            }
            return false;
        }catch (Exception e){
            customResponse(5000001,"系统异常",servletResponse);
            return false;
        }
        return true;
    }

    /**
     * 异常处理
     * 因为这里的位置是高于业务层的,所以这里的异常只能通过流的形式输出到前端。
     * @param code
     * @param msg
     * @param response
     */
    private void customResponse(int code, String msg, ServletResponse response) {
        // 自定义异常的类,用户返回给客户端相应的JSON格式的信息
        try {
            Map<String, Object> result = new HashMap<>();
            result.put("code", code);
            result.put("msg", msg);
            response.setContentType("application/json; charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            String userJson = JSON.toJSONString(result);
            // 写入到 流中,返回到客户端
            OutputStream out = response.getOutputStream();
            out.write(userJson.getBytes(StandardCharsets.UTF_8));
            out.flush();
        } catch (IOException e) {
            log.error("eror={}", e.getLocalizedMessage());
        }
    }
}

3. ShiroUsernamePasswordToken

package com.feng.shiro;

import org.apache.shiro.authc.UsernamePasswordToken;

public class ShiroUsernamePasswordToken extends UsernamePasswordToken {

    private String token;

    public ShiroUsernamePasswordToken(String token) {
        this.token = token;
    }

    @Override
    public Object getPrincipal() {
        return token;
    }

    @Override
    public Object getCredentials() {
        return token;
    }
}

4. ShiroRealm

package com.feng.shiro;

import com.feng.bean.SysUser;
import com.feng.service.PermissionService;
import com.feng.service.RoleService;
import com.feng.service.UserService;
import com.feng.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Slf4j
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Resource
    private RoleService roleService;

    @Resource
    private PermissionService permissionService;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 设置支持令牌校验
     *
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof ShiroUsernamePasswordToken;
    }

    /**
     * 授权
     * 主要业务:
     * 系统业务出现要验证用户的角色权限的时候,就会调用这个方法
     * 来获取该用户所拥有的角色/权限
     * 这个用户授权的方法我们可以缓存起来不用每次都调用这个方法。
     * 后续的课程我们会结合 redis 实现它
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("ShiroRealm.doGetAuthorizationInfo()");
        String token= (String) principalCollection.getPrimaryPrincipal();
        String userId= (String) redisUtil.get(token);
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();

        //返回该用户的 角色信息 给授权器
        List<String> roleNames = roleService.getRoleNamesByUserId(userId);
        if (null != roleNames && !roleNames.isEmpty()) {
            info.addRoles(roleNames);
        }
        //返回该用户的 权限信息 给授权器
        Set<String> permissionPerms = permissionService.getPermissionPermsByUserId(userId);
        if (permissionPerms != null) {
            info.addStringPermissions(permissionPerms);
        }
        return info;
    }

    /**
     * 认证
     * 主要业务:
     * 当业务代码调用 subject.login(customPasswordToken); 方法后
     * 就会自动调用这个方法 验证用户名/密码
     * 这里我们改造成 验证 token 是否有效 已经自定义了 shiro 验证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("ShiroRealm.doGetAuthenticationInfo()");
        ShiroUsernamePasswordToken token = (ShiroUsernamePasswordToken) authenticationToken;
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo((String)token.getPrincipal(), (String)token.getCredentials(), ShiroRealm.class.getName());
        return info;
    }

    private List<String> getRoleByUserId(String userId){
        List<String> roles=new ArrayList<>();
        if(userId.equals("8a938151-53e6-4182-925a-684f3be840e8")){
            roles.add("admin");
        }
        roles.add("test");
        return roles;
    }

    private List<String> getPermissionsByUserId(String userId){
        List<String> permissions=new ArrayList<>();
        if(userId.equals("8a938151-53e6-4182-925a-684f3be840e8")){
            permissions.add("*");
        }
        permissions.add("sys:user:detail");
        permissions.add("sys:user:edit");
        return permissions;
    }
}

5. ShiroHashedCredentialsMatcher

public class ShiroHashedCredentialsMatcher extends HashedCredentialsMatcher {

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        ShiroUsernamePasswordToken shiroUsernamePasswordToken= (ShiroUsernamePasswordToken) token;
        String accessToken = (String) shiroUsernamePasswordToken.getPrincipal();
        if(!redisUtil.hasKey(accessToken)){
            throw new BusinessException(4001002,"授权信息信息无效请重新登录");
        }
        return true;
    }
}

三、业务逻辑控制层代码

package com.feng.controller;

import com.feng.bean.SysUser;
import com.feng.service.UserService;
import com.feng.vo.LoginReqVO;
import com.feng.vo.LoginRespVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/user")
@Api(tags = "用户模块",description = "用户模块相关接口")
public class LoginController {

    @Autowired
    private UserService userService;

    @GetMapping("/page")
    public String index() {
        return "login";
    }

    /**
     * 前端用表单发请求如果使用 form-data、x-www-form-urlencoded 获取 ,则不可用 @RequestBody接受(因为他接受的为json)
     * @param loginReqVO
     * @return
     */
    @ApiOperation(value = "用户登录接口")
    @PostMapping(value = "/login")
    @ResponseBody
    public Map<String, Object> loginUser(@RequestBody LoginReqVO loginReqVO) {
        LoginRespVO info = userService.login(loginReqVO);
        Map<String, Object> result = new HashMap<>();
        result.put("code", 0);
        result.put("data", info);
        return result;
    }

    @ApiOperation(value = "获取用户详情接口")
    @GetMapping("/getuser/{id}")
    @RequiresPermissions("sys:user:detail")
    public Map<String, Object> getUserAllInfo(@PathVariable("id") String id){
        Map<String, Object> result = new HashMap<>();
        SysUser detail = userService.detail(id);
        result.put("code", 0);
        result.put("data", detail);
        return result;
    }

    @GetMapping("/test")
    public Map<String, Object> test(){
        Map<String, Object> result = new HashMap<>();
        result.put("code", 0);
        result.put("data", "sucess");
        return result;
    }
}

五、postman测试和debug分析

1. 登录

登录的URL 在 ShiroConfig.shiroFilterFactoryBean() 方法中已经被设置成了白名单,在shiro的各处打了断电,也不会进入。直接进入到控制器层返回用户id和token。

http://localhost:8082/user/login
{
    "username": "feng",
    "password": "666666"
}

在这里插入图片描述

2. 获取用户信息

此URL 已经被设置走自定义的 ShiroAccessControlFilter 过滤器。
所以debug发请求分析如下:

  1. 先进入 ShiroAccessControlFilter.isAccessAllowed() 方法
  2. 进入到源码 AccessControlFilter.onPreHandle() 方法,这个方法会调用上面的方法和下面的方法
  3. 在进入到 ShiroAccessControlFilter.onAccessDenied() 方法,在这里获取token,并简单验证token是否存在,然后进行 shiro的主体登录。(一会儿,还会返回来)
  4. 主体登录后,debug 跳转到 ShiroRealm.doGetAuthenticationInfo() 进行认证。
  5. 然后流转到 自定义的核心验证类和方法ShiroHashedCredentialsMatcher.doCredentialsMatch() 方法 。
  6. 然后返回到第三步 的 ShiroAccessControlFilter.onAccessDenied() 方法 的最后一行返回值,返回值为 true。
  7. 然后流转到 ShiroRealm.doGetAuthorizationInfo() 进行授权。这里进入到授权方法是因为在控制器方法上有注解:@RequiresPermissions("sys:user:detail")
http://localhost:8082/user/getuser/8a938151-53e6-4182-925a-684f3be840e8

在这里插入图片描述

六、注意的点

1. 数据库表的设计

用户登录只涉及到 user 表
shiro的权限授权部分涉及到 role、permission、user_role、role_permission 表。

2. shiro的认证授权流程

一定要多分析下shiro的认证流程,代码执行流程的走向。

相关文章
|
7月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
477 7
|
7月前
|
人工智能 Java 数据库
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
|
6月前
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
564 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
5月前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
567 0
|
9月前
|
云安全 安全 数据建模
《数字证书:互联网世界的"身份证"与"防盗门"》 ——揭秘网络安全背后的加密江湖
在2023年某深夜,上海陆家嘴金融公司机房遭遇黑客攻击,神秘青铜大门与九大掌门封印的玉牌突现,阻止了入侵。此门象征数字证书,保障网络安全。数字证书如验钞机识别假币,保护用户数据。它通过SSL/TLS加密、CA认证和非对称加密,构建安全通信。证书分为DV、OV、EV三类,分别适合不同场景。忽视证书安全可能导致巨额损失。阿里云提供一站式证书服务,助力企业部署SSL证书,迎接未来量子计算和物联网挑战。
|
11月前
|
安全 算法 网络协议
【网络原理】——图解HTTPS如何加密(通俗简单易懂)
HTTPS加密过程,明文,密文,密钥,对称加密,非对称加密,公钥和私钥,证书加密
|
11月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
215 10
|
11月前
|
存储 SQL 安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将介绍网络安全的重要性,分析常见的网络安全漏洞及其危害,探讨加密技术在保障网络安全中的作用,并强调提高安全意识的必要性。通过本文的学习,读者将了解网络安全的基本概念和应对策略,提升个人和组织的网络安全防护能力。
|
11月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的内容,并提供一些实用的代码示例。通过阅读本文,您将了解到如何保护自己的网络安全,以及如何提高自己的信息安全意识。
218 10
|
11月前
|
SQL 安全 网络安全
网络安全漏洞、加密技术与安全意识的知识分享
随着互联网的普及,网络安全问题日益严重。本文将介绍网络安全漏洞的概念、类型和防范措施,以及加密技术的原理和应用。同时,强调提高个人和企业的安全意识对于防范网络攻击的重要性。
346 7