微服务开发系列 第九篇:OAuth2

news2024/11/18 3:33:56

总概

A、技术栈

  • 开发语言:Java 1.8
  • 数据库:MySQL、Redis、MongoDB、Elasticsearch
  • 微服务框架:Spring Cloud Alibaba
  • 微服务网关:Spring Cloud Gateway
  • 服务注册和配置中心:Nacos
  • 分布式事务:Seata
  • 链路追踪框架:Sleuth
  • 服务降级与熔断:Sentinel
  • ORM框架:MyBatis-Plus
  • 分布式任务调度平台:XXL-JOB
  • 消息中间件:RocketMQ
  • 分布式锁:Redisson
  • 权限:OAuth2
  • DevOps:Jenkins、Docker、K8S

B、本节实现目标

  • 新建mall-auth服务,完成授权功能

一、OAuth2.0介绍

OAuth(开发授权)是一个开放标准,允许用户授权第三方应用,访问他们存储在另外的服务提供者上的信息。而不需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。OAuth2.0是OAuth协议的延续版,但不兼容OAuth1.0(OAuth1.0已被完全废止)。

二、spring-cloud-starter-oauth2使用

2.1 Spring-Security-OAuth2介绍

Spring Security OAuth2是对OAuth2.0协议的一种实现,并且和Spring Sercurity相辅相成,属于Spring Cloud的体系,与Spring Boot的集成相当便利。在OAuth2.0的协议里包括两个服务提供方,授权服务(也叫认证服务)、资源服务。使用Spring Security OAuth2的时候可以把这两个服务放到同一个应用里面(生产环境不会这样干),也可以建立一个授权服务,对多个资源服务进行授权。

2.2 pom.xml依赖

SpringCloud微服务全家桶中有spring-cloud-starter-security依赖组件,并且spring-cloud-starter-oauth2依赖了spring-cloud-starter-securityspring-cloud-starter-security依赖了spring-boot-starter-security,因此添加spring-cloud-starter-oauth2即可。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
    <version>2.2.4.RELEASE</version>
</dependency>

三、架构说明

认证服务(mall-auth)负责认证授权,网关服务(mall-gateway)负责校验认证和鉴权,其他API服务负责处理自己的业务逻辑。安全相关的逻辑只存在于认证服务和网关服务中,其他服务只是单纯地提供服务而没有任何安全相关逻辑。

具体服务:

  • [mall-auth]:认证服务,负责对登录用户进行认证授权颁发token。
  • [mall-gateway]:网关服务,负责请求转发和校验认证和鉴权。
  • [mall-member]:受保护的API服务,用户鉴权通过后可以访问该服务,该类服务还有[mall-product]、[mall-search]等等。

四、代码实现

4.1 mall-oauth2-module模块

新建mall-oauth2-module模块,该模块被mall-auth和后面的mall-gateway所依赖。

4.1.1 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>mall-pom</artifactId>
        <groupId>com.ac</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupId>com.ac</groupId>
    <artifactId>mall-oauth2-module</artifactId>
    <version>${mall.version}</version>
    <name>mall-oauth2-module</name>
    <description>oauth2模块</description>

    <dependencies>

        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.4.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

4.1.2 项目结构

mall-oauth2-module

具体实现代码可参看源码。

4.2 mall-auth服务

新建mall-auth服务,接入OAuth2,颁发token,将token存在redis。

4.2.1 数据库脚本

CREATE TABLE `oauth_client_details` (
    `client_id` VARCHAR(128)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
    `resource_ids` VARCHAR(256)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    `client_secret` VARCHAR(256)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    `scope` VARCHAR(256)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    `authorized_grant_types` VARCHAR(256)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    `web_server_redirect_uri` VARCHAR(256)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    `authorities` VARCHAR(256)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    `access_token_validity` INT DEFAULT NULL,
    `refresh_token_validity` INT DEFAULT NULL,
    `additional_information` VARCHAR(4096)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    `autoapprove` VARCHAR(256)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    `client_secret_str` VARCHAR(20)CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
    PRIMARY KEY (`client_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;

INSERT INTO `oauth_client_details` VALUES ('app',NULL,'$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO','all','APP_SMS,APP_ONE_KEY,APP_SOCIAL,APP_PWD,ADMIN_PWD,APP_SOCIAL,APP_ANONYMOUS,APP_QRCODE,authorization_code,password,refresh_token','http://a.qimiao.com',NULL,2592000,2592000,NULL,NULL,'app'),('h5',NULL,'$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO','all','APP_SMS,APP_ONE_KEY,APP_SOCIAL,APP_PWD,ADMIN_PWD,APP_SOCIAL,APP_ANONYMOUS,APP_QRCODE,authorization_code,password,refresh_token',NULL,NULL,2592000,2592000,NULL,NULL,'app'),('mini',NULL,'$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO','all','APP_SMS,APP_ONE_KEY,APP_SOCIAL,APP_PWD,ADMIN_PWD,APP_SOCIAL,APP_ANONYMOUS,APP_QRCODE,authorization_code,password,refresh_token',NULL,NULL,2592000,2592000,NULL,NULL,'app'),('web',NULL,'$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO','all','APP_SMS,APP_ONE_KEY,APP_SOCIAL,APP_PWD,ADMIN_PWD,APP_SOCIAL,APP_ANONYMOUS,APP_QRCODE,authorization_code,password,refresh_token',NULL,NULL,2592000,2592000,NULL,NULL,'app');

4.2.2 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>mall-pom</artifactId>
        <groupId>com.ac</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupId>com.ac</groupId>
    <artifactId>mall-auth</artifactId>
    <version>${mall.version}</version>
    <name>mall-auth</name>
    <description>授权服务</description>

    <dependencies>
        <dependency>
            <groupId>com.ac</groupId>
            <artifactId>mall-core</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.ac</groupId>
            <artifactId>mall-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.ac</groupId>
            <artifactId>mall-oauth2</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>

        <dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>nimbus-jose-jwt</artifactId>
            <version>9.31</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

4.2.3 AuthController

package com.ac.auth.controller;

import com.ac.auth.component.AuthRedisHelper;
import com.ac.auth.component.AuthTokenComponent;
import com.ac.auth.dto.Oauth2TokenDTO;
import com.ac.oauth2.enums.SecurityLoginTypeEnum;
import com.ac.auth.util.IpUtil;
import com.ac.auth.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jodd.util.StringUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Api(tags = "会员授权")
@RestController
@RequestMapping("oauth")
public class AuthController {

    @Resource
    private AuthTokenComponent authTokenComponent;

    @Resource
    private AuthRedisHelper authRedisHelper;

    @Resource
    private RedissonClient redissonClient;

    @SneakyThrows
    @PostMapping("pwdLogin")
    @ApiOperation(value = "密码登录")
    public Oauth2TokenDTO pwdLogin(@RequestBody MemberLoginPwdVO vo, HttpServletRequest request) {
        if (StringUtil.isEmpty(vo.getClientId())) {
            vo.setClientId("app");
        }
        vo.setIp(IpUtil.ip(request));
        Map<String, String> params = getMemberBaseParam(vo, SecurityLoginTypeEnum.APP_PWD.getCode());
        params.put("mobile", vo.getMobile());
        params.put("password", vo.getPassword());
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        Oauth2TokenDTO oauth2Token = authTokenComponent.getAccessToken(vo.getClientId(), "app", grantedAuthorities, params);
        return oauth2Token;
    }

    @SneakyThrows
    @PostMapping("msgCodeLogin")
    @ApiOperation(value = "短信验证码登录")
    public Oauth2TokenDTO msgCodeLogin(@RequestBody MemberLoginMsgCodeVO vo, HttpServletRequest request) {
        log.info("msgCodeLogin:mobile={}", vo.getMobile());
        RLock rdsLock = redissonClient.getLock(vo.getMobile());
        try {
            rdsLock.lock(5, TimeUnit.SECONDS);
            Boolean delRecord = authRedisHelper.getDelRecord(vo.getMobile());
            if (delRecord) {
                throw new RuntimeException("用户已注销");
            }

            vo.setIp(IpUtil.ip(request));
            Map<String, String> params = getMemberBaseParam(vo, SecurityLoginTypeEnum.APP_SMS.getCode());
            params.put("globalCode", vo.getGlobalCode());
            params.put("mobile", vo.getMobile());
            params.put("code", vo.getMsgCode());
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
            Oauth2TokenDTO oauth2Token = authTokenComponent.getAccessToken(vo.getClientId(), "app", grantedAuthorities, params);
            return oauth2Token;
        } finally {
            // 释放锁
            if (rdsLock.isLocked()) {
                rdsLock.unlock();
            }
        }
    }

    @SneakyThrows
    @PostMapping("oneKeyLogin")
    @ApiOperation(value = "一键登录")
    public Oauth2TokenDTO oneKeyLogin(@RequestBody MemberLoginOneKeyVO vo, HttpServletRequest request) {
        vo.setIp(IpUtil.ip(request));
        Map<String, String> params = getMemberBaseParam(vo, SecurityLoginTypeEnum.APP_ONE_KEY.getCode());
        params.put("token", vo.getToken());
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        Oauth2TokenDTO oauth2Token = authTokenComponent.getAccessToken(vo.getClientId(), "app", grantedAuthorities, params);
        return oauth2Token;
    }

    @SneakyThrows
    @PostMapping("socialLogin")
    @ApiOperation(value = "第三方登录")
    public Oauth2TokenDTO socialLogin(@RequestBody MemberLoginSocialVO vo, HttpServletRequest request) {
        RLock rdsLock = redissonClient.getLock(vo.getAcc());
        try {
            rdsLock.lock(5, TimeUnit.SECONDS);
            if (StringUtil.isEmpty(vo.getClientId())) {
                vo.setClientId("app");
            }
            vo.setIp(IpUtil.ip(request));
            Map<String, String> params = getMemberBaseParam(vo, SecurityLoginTypeEnum.APP_SOCIAL.getCode());
            params.put("platform", vo.getPlatform());
            params.put("socialType", vo.getSocialType().getCode());
            params.put("acc", vo.getAcc());
            params.put("uid", vo.getUid());
            params.put("iconUrl", vo.getIconUrl());
            params.put("nickName", vo.getNickName());

            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
            Oauth2TokenDTO oauth2Token = authTokenComponent.getAccessToken(vo.getClientId(), "app", grantedAuthorities, params);
            return oauth2Token;
        } finally {
            // 释放锁
            if (rdsLock.isLocked()) {
                rdsLock.unlock();
            }
        }
    }

    @SneakyThrows
    @PostMapping("visitor")
    @ApiOperation(value = "游客登录")
    public Oauth2TokenDTO visitorLogin(@RequestBody MemberLoginVisitorVO vo, HttpServletRequest request) {
        vo.setIp(IpUtil.ip(request));
        Map<String, String> params = getMemberBaseParam(vo, SecurityLoginTypeEnum.APP_ANONYMOUS.getCode());
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        Oauth2TokenDTO oauth2Token = authTokenComponent.getAccessToken(vo.getClientId(), "app", grantedAuthorities, params);
        return oauth2Token;
    }

    private Map<String, String> getMemberBaseParam(MemberLoginBaseVO vo, String grantType) {
        Map<String, String> params = new HashMap<>();
        params.put("client_id", vo.getClientId());
        params.put("client_secret", "app");
        params.put("grant_type", grantType);
        params.put("scope", "all");
        params.put("platform", vo.getPlatform());
        //附加信息
        params.put("version", vo.getVersion());
        params.put("device", vo.getDevice());
        params.put("iemi", vo.getIemi());
        params.put("location", vo.getLocation());
        params.put("ip", vo.getIp());
        params.put("recommendCode", vo.getRecommendCode());
        return params;
    }
}

mall-auth项目结构

五、测试

5.1 账号密码

账号密码

5.2 短信验证码

短信验证码

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS查缺补漏之《说一说CSS3有哪些新特性?》

面试时经常会被用到你了解CSS3新特性嘛&#xff0c;针对此问题&#xff0c;特整理如下~ 背景相关 background-size&#xff1a;用于设置背景图的尺寸 可选属性值有 length、percentage、cover、contain、auto length用长度值规定背景图片大小&#xff0c;若有两值&#xff0c;…

阿里云无影云电脑使用教程(3分钟新手指南)

​阿里云无影云电脑即无影云桌面&#xff0c;云桌面如何使用&#xff1f;云电脑创建后没有用户名和密码&#xff0c;先创建用户设置密码&#xff0c;才可以登录连接到云桌面。云桌面想要访问公网还需要开通互联网访问功能。阿里云百科来详细说下阿里云无影云电脑从选择、创建用…

项目管理,如何做到流程标准化?

项目管理如何做到刘春标准化&#xff1f;要想做好项目管理&#xff0c;可以借助于信息化工具&#xff0c;从以下方面入手&#xff1a; 1.明确目标 在项目管理中&#xff0c;确定团队的目标是非常重要的。团队需要制定一个清晰、可衡量的目标&#xff0c;以便能够全力以赴地实…

sqlserver------数据库的存储过程(练习)

对于数据库的存储过程之前的专题有讲过 这里具体讲述存储过程的编写方法&#xff1a; 例题&#xff1a;有heat表和eatables两张表&#xff0c;分别为&#xff1a; eatables heat&#xff1a;protein&#xff08;蛋白质&#xff09;&#xff0c;fat&#xff08;脂肪&#xff…

【计算机网络自顶向下】如何学好计网-第四章网络层

第四章 网络层 学习目的&#xff1a; 理解网络层服务的主要原理 网络岑服务模型转发&#xff08;forwarding&#xff09;和路由&#xff08;routing&#xff09;的概念对比路由器的工作原理路由算法及路由协议 完成简单的组网及IP地址和路由配置 4.1 引言 网络层提供的功能…

前端vue自定义简单实用下拉筛选 下拉菜单

前端vue自定义简单实用下拉筛选 下拉菜单, 下载完整代码请访问: https://ext.dcloud.net.cn/plugin?id13020 效果图如下: #### 使用方法 使用方法 <!-- titleArr: 选择项数组 dropArr: 下拉项数组 finishDropClick: 下拉筛选完成事件--> <ccDropDownMenu :titleA…

解密Prompt系列3. 冻结LM微调Prompt: Prefix-tuning Prompt-tuning P-tuning

这一章我们介绍在下游任务微调中固定LM参数&#xff0c;只微调Prompt的相关模型。这类模型的优势很直观就是微调的参数量小&#xff0c;能大幅降低LLM的微调参数量&#xff0c;是轻量级的微调替代品。和前两章微调LM和全部冻结的prompt模板相比&#xff0c;微调Prompt范式最大的…

21. 算法之动态规划

1. 概念 动态规划(Dynamic Programming)&#xff0c;是一种分阶段求解的方法。动态规划算法是通过拆分问题&#xff0c;定义问题状态和状态之间的关系&#xff0c;使得问题能够以递推&#xff08;或者说分治&#xff09; 的方式去解决。 首先是拆分问题&#xff0c;就是根据问…

生产报工软件怎么选?一定要看这几点,值得收藏!

生产报工软件怎么选&#xff1f; 适合项目型企业&#xff0c;支持移动端报工&#xff1b;可以进行工时上报、工时统计、人力成本核算&#xff1b;满足中大型企业需求。 题主的要求可以说非常具有代表性了&#xff0c;今天我们就来看一看如何寻找到这样的报工系统。 一、为什…

Alibaba Cloud Linux安装Nginx以及常用命令

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装C编译器&#xff0c;以及所需要的库二、下载和安装PCRE三.Ngxin相关命令 总结 前言 提示&#xff1a;系统是Alibaba Cloud Linux 3.2104 LTS 64位&…

批量更新状态功能在设备巡检、人员管理、工序流转等场景的应用

二维码已被应用在了各式各样的场景中&#xff0c;譬如教育培训、会议签到、产品展示等等。其中有很多场景需要一次性运用到大量的二维码&#xff0c;如人员管理、工序流转、设备巡检等&#xff0c;可以使用批量添加记录功能使工作效率近一步提升。 原先为一批二维码添加记录时…

dubbo3 Cluster wrapper初始化及extensionloader分析

从以下代码&#xff0c;可以看到dubbo默认的服务是failover SPI("failover") public interface Cluster {String DEFAULT "failover";Adaptive<T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcExce…

达梦MPP集群搭建、DEM管理工具搭建MPP集群应用

说明... 3 两节点MPP集群手动搭建... 4 1、配置dm.ini 4 2、配置dmmal.ini 5 3、配置dmmpp.ctl 5 4、启动EP01和EP02数据库实例&#xff0c;系统搭建完成。... 6 MPP使用&#xff1a;... 6 使用DEM管理系统搭建MPP3节点集群... 10 一、达梦DEM部署... 11 1、创建DEM库…

计算机网络管理 常见的计算机网络管理工具snmputil,Mib browser,SNMPc管理软件的功能和异同

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

【C++ 基础篇:25】:【重要模板】C++ 算术(赋值)运算符重载及自增自减运算符重载【以 Date 日期类为例】

系列文章说明 本系列 C 相关文章 仅为笔者学习笔记记录&#xff0c;用自己的理解记录学习&#xff01;C 学习系列将分为三个阶段&#xff1a;基础篇、STL 篇、高阶数据结构与算法篇&#xff0c;相关重点内容如下&#xff1a; 基础篇&#xff1a;类与对象&#xff08;涉及C的三大…

LabVIEW开发监测太阳能电池和损伤检测

LabVIEW开发监测太阳能电池和损伤检测 使用LabVEW监测太阳能电池的实时数据&#xff0c;利用LabVIEW实现太阳能跟踪和损伤检测。使用了太阳能电池板&#xff0c;Arduino UNO板&#xff0c;电压&#xff08;0-25V&#xff09;传感器LDR&#xff0c;温度传感器和伺服电机。Solar…

基于ubuntu20.4搭建的K8S集群新增工作节点带GPU显卡过程记录

基于ubuntu20.4搭建的K8S集群新增工作节点带GPU显卡过程记录 1、创建虚拟机引导选择efi 2、添加显卡,修改虚拟机-高级参数,添加以下两个参数 pciPassthru.64bitMMIOSizeGB:192 pciPassthru.use64bitMMIO:TRUE否则可能无法开机。 3、添加直通显卡,安装显卡驱动。 3.1、查…

Redis集群详细介绍从0开始-包括集群的Jedis开发

集群 为什么需要集群-高可用性 1、生产环境的实际需求和问题 容量不够&#xff0c;redis 如何进行扩容&#xff1f;并发写操作&#xff0c; redis 如何分摊&#xff1f;主从模式&#xff0c;薪火相传模式&#xff0c;主机宕机&#xff0c;会导致ip 地址发生变化&#xff0c;…

linuxOPS系统服务_linux文件权限管理

什么是权限 **权限&#xff1a;**在计算机系统中&#xff0c;权限是指某个计算机用户具有使用软件资源的权利。 权限的目的 文件权限的设置目的&#xff1a;是想让某个用户有权利操作文件 权限的分类 普通权限rwx 用户正常情况去操作文件所具有的权限 高级权限st 用户对某…

FPGA基础知识-任务和函数

目录 学习目标 学习内容 1.任务和函数的区别 2.任务 3.函数 学习时间 学习总结 学习目标&#xff1a; 1.理解任务和函数之间的区别。 2.理解定义任务所需的条件&#xff0c;学会任务的声明和调用。 3.理解定义函数所需的条件&#xff0e;学会函数的声明和调用。 学习…