精华内容
下载资源
问答
  • 3D内容平台是华为提供的致力于打造成为全领域内容聚合的分发服务平台,为开发者搭建一个内容交流的桥梁,从而构建华为AR/VR等领域下的优质内容体验。 2 平台定位 创意指导:合作场景广泛,AR 教育,AR 电商,AR ...

     

    1 平台概述

    3D内容平台是华为提供的致力于打造成为全领域内容聚合的分发服务平台,为开发者搭建一个内容交流的桥梁,从而构建华为AR/VR等领域下的优质内容体验。

    2 平台定位

    创意指导:合作场景广泛,AR 教育,AR 电商,AR 家居,AR 游戏 等等

    发布展示:便捷的发布流程,优质的模型展示

    在线编辑:场景开发IDE,高效便捷的完成交互式3D AR场景开发

    多平台分享:多渠道分享,多领域应用分发

    3 平台优势

     
    4 平台功能介绍

    4.1 3D模型素材库

    平台提供各类型风格3D模型素材,内容涵盖运动科学、文化艺术、家居建筑、自然风景、娱乐、直播、游戏、汽车、测量、广告等各个方面

    4.2 3D模型一站式创建发布

     
    4.3 六大行业解决方案

    六大行业解决方案:AR娱乐、AR直播、AR游戏、AR汽车、AR测量、AR广告

    以上就是关于我们【3D内容平台】的介绍啦,有任何问题欢迎在原帖子底部留言,我们会及时为您解答~

    原帖子链接:https://developer.huawei.com/...

    原作者:TOTORO

    展开全文
  • Dapp开发实战:去中心化NFT交易平台

    千次阅读 热门讨论 2021-07-04 20:28:46
    在以太坊上建立数字市场 在本次实战所使用的技术是React, Next.js, Tailwind CSS, RemixIDE, Solidity, Ethers. 编写智能合约 市场将由两个主要的智能合约组成: 用于铸造 NFT的NFT合约 和 促进 NFT销售的市场合约 ...

    在以太坊上建立数字市场

    在本次实战所使用的技术是React, Next.js, Tailwind CSS, RemixIDE, Solidity, Ethers.

    编写智能合约
    市场将由两个主要的智能合约组成:
    用于铸造 NFT的NFT合约 促进 NFT销售的市场合约

    为了编写 NFT,我们可以使用OpenZeppelin获得的ERC721标准。
    参考:https://docs.openzeppelin.com/contracts/4.x/erc721

    contract NFT is ERC721URIStorage {
        using Counters for Counters.Counter;
        Counters.Counter private _tokenIds;
        address contractAddress;
    
        constructor(address marketplaceAddress) ERC721("Xia Blocks NFTs", "XBNFT") {
            contractAddress = marketplaceAddress;
        }//合约可以允许市场合约批准将代币从所有者转移到卖家
        function createToken(string memory tokenURI) public returns (uint) {
            _tokenIds.increment();
            uint256 newItemId = _tokenIds.current();
            _mint(msg.sender, newItemId);
            _setTokenURI(newItemId, tokenURI);
            setApprovalForAll(contractAddress, true);
            return newItemId;
        }
    }
    
    

    编写市场合约
    继承ReentrancyGuard:有助于防止对函数的可重入调用的合同模块

    // SPDX-License-Identifier: XXL
    pragma solidity ^0.8.3;
    import "@openzeppelin/contracts/utils/Counters.sol";
    import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
    import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
    import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
    
    contract NFTMarket is ReentrancyGuard {
      using Counters for Counters.Counter;
      Counters.Counter private _itemIds;
      Counters.Counter private _itemsSold;
      uint[] marketItems;
    	//存储记录
      struct MarketItem {
        uint itemId;
        address nftContract;
        uint256 tokenId;
        address payable seller;
        address payable owner;
        uint256 price;
      }
    
      mapping(uint256 => MarketItem) private idToMarketItem;
    
      event MarketItemCreated (
        uint indexed itemId,
        address indexed nftContract,
        uint256 indexed tokenId,
        address seller,
        address owner,
        uint256 price
      );
    
      function getMarketItem(uint256 marketItemId) public view returns (MarketItem memory) {
        return idToMarketItem[marketItemId];
      }
    
      function createMarketItem(
        address nftContract,
        uint256 tokenId,
        uint256 price
      ) public payable nonReentrant {
        require(price > 0, "Price must be at least 1 wei");
    
        _itemIds.increment();
        uint256 itemId = _itemIds.current();
        marketItems.push(itemId);
      
        idToMarketItem[itemId] =  MarketItem(
          itemId,
          nftContract,
          tokenId,
          payable(msg.sender),
          payable(address(0)),
          price
        );
    
        IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId);
    
        emit MarketItemCreated(
          itemId,
          nftContract,
          tokenId,
          msg.sender,
          address(0),
          price
        );
      }
    
      function createMarketSale(
        address nftContract,
        uint256 itemId
        ) payable public {
        uint price = idToMarketItem[itemId].price;
        uint tokenId = idToMarketItem[itemId].tokenId;
        require(msg.value == price, "Please submit the asking price in order to complete the purchase");
    
        idToMarketItem[itemId].seller.transfer(msg.value);
        IERC721(nftContract).transferFrom(address(this), msg.sender, tokenId);
        idToMarketItem[itemId].owner = payable(msg.sender);
        _itemsSold.increment();
      }
    
      function fetchMarketItem(uint itemId) public view returns (MarketItem memory) {
        MarketItem memory item = idToMarketItem[itemId];
        return item;
      }
    	//返回所有仍在销售的市场商品
      function fetchMarketItems() public view returns (MarketItem[] memory) {
        uint itemCount = _itemIds.current();
        uint unsoldItemCount = _itemIds.current() - _itemsSold.current();
        uint currentIndex = 0;
    
        MarketItem[] memory items = new MarketItem[](unsoldItemCount);
        for (uint i = 0; i < itemCount; i++) {
          if (idToMarketItem[i + 1].owner == address(0)) {
            uint currentId = idToMarketItem[i + 1].itemId;
            MarketItem storage currentItem = idToMarketItem[currentId];
            items[currentIndex] = currentItem;
            currentIndex += 1;
          }
        }
       
        return items;
      }
    	//返回用户已购买的NFT
      function fetchMyNFTs() public view returns (MarketItem[] memory) {
        uint totalItemCount = _itemIds.current();
        uint itemCount = 0;
        uint currentIndex = 0;
        for (uint i = 0; i < totalItemCount; i++) {
          if (idToMarketItem[i + 1].owner == msg.sender) {
            itemCount += 1;
          }
        }
        MarketItem[] memory items = new MarketItem[](itemCount);
        for (uint i = 0; i < totalItemCount; i++) {
          if (idToMarketItem[i + 1].owner == msg.sender) {
            uint currentId = idToMarketItem[i + 1].itemId;
            MarketItem storage currentItem = idToMarketItem[currentId];
            items[currentIndex] = currentItem;
            currentIndex += 1;
          }
        }
        return items;
      }
    }
    
    

    编写前端
    首页
    在这里插入图片描述

    Home页面:使用web3Modal加载钱包连接以太坊网络
    调用合约函数fetchMarketItems加载页面

      const [nfts, setNfts] = useState([])
      const [loaded, setLoaded] = useState('not-loaded')
      useEffect(() => {
        loadNFTs()
      }, [])
      
     async function loadNFTs() {
        const providerOptions = {
          fortmatic: {
            package: Fortmatic,
            options: {
              // Mikko's TESTNET api key
              key: "pk_test_391E26A3B43A3350"
            }
          },
          walletconnect: {
            package: WalletConnectProvider, // required
            options: {
              infuraId: "INFURA_ID" // required
            }
          }
        };
        const web3Modal = new Web3Modal({
          network: "mainnet",
          cacheProvider: true,
          disableInjectedProvider: false,
          providerOptions: providerOptions, // required
        });
        const connection = await web3Modal.connect()
        const provider = new ethers.providers.Web3Provider(connection)
        const tokenContract = new ethers.Contract(nftaddress, nftabi, provider)
        const marketContract = new ethers.Contract(nftmarketaddress, nftmarketabi, provider)
        const data = await marketContract.fetchMarketItems()
    
        const items = await Promise.all(data.map(async i => {
          const tokenUri = await tokenContract.tokenURI(i.tokenId)
          const meta = await axios.get(tokenUri)
          let price = web3.utils.fromWei(i.price.toString(), 'ether');
          let item = {
            price,
            tokenId: i.tokenId.toNumber(),
            seller: i.seller,
            owner: i.owner,
            image: meta.data.image,
            name: meta.data.name,
            description: meta.data.description,
          }
          return item
        }))
        console.log('items: ', items)
        setNfts(items)
        setLoaded('loaded')
      }
    

    Create NFT 铸币页面(信息上传ipfs返回链接作为tokenURI)
    在这里插入图片描述

    const client = ipfsHttpClient('https://ipfs.infura.io:5001/api/v0')
      const [fileUrl, setFileUrl] = useState(null)
      const [formInput, updateFormInput] = useState({ price: '', name: '', description: '' })
      const router = useRouter()
    
      async function createSale(url) {
        const web3Modal = new Web3Modal({
          network: "mainnet",
          cacheProvider: true,
        });
        const connection = await web3Modal.connect()
        const provider = new ethers.providers.Web3Provider(connection)    
        const signer = provider.getSigner()
        
        let contract = new ethers.Contract(nftaddress,nftabi, signer)
        let transaction = await contract.createToken(url)
        let tx = await transaction.wait()
        let event = tx.events[0]
        let value = event.args[2]
        let tokenId = value.toNumber()
        const price = web3.utils.toWei(formInput.price, 'ether')
      
        const listingPrice = web3.utils.toWei('0.1', 'ether')
    
        contract = new ethers.Contract(nftmarketaddress, nftmarketabi, signer)
        transaction = await contract.createMarketItem(nftaddress, tokenId, price, { value: listingPrice })
        
        await transaction.wait()
        router.push('/')
      }
     async function onChange(e) {
        const file = e.target.files[0];
        try {
          const added = await client.add(
            file,
            {
              progress: (prog) => console.log(`received: ${prog}`)
            }
          )
          const url = `https://ipfs.infura.io/ipfs/${added.path}`
          setFileUrl(url)
        } catch (error) {
          console.log('Error uploading file: ', error);
        }  
      }
      
      async function createMarket() {
        const { name, description, price } = formInput
        if (!name || !description || !price || !fileUrl) return
        // first, upload to IPFS
        const data = JSON.stringify({
          name, description, image: fileUrl
        })
        try {
          const added = await client.add(data)
          const url = `https://ipfs.infura.io/ipfs/${added.path}`
          createSale(url)
        } catch (error) {
          console.log('Error uploading file: ', error);
        }  
      }
      
    
    
    

    MyNFT 同上loadNFTS一样,不过调用合约fetchMyNFTs
    在这里插入图片描述
    完整代码已放置Gitee https://gitee.com/xiaxuliang/nftmakret

    展开全文
  • 2021年十佳返利优惠券平台排名如下

    千次阅读 2021-09-28 15:21:30
    2021年十佳优惠券返利app排名 2021年十佳返利优惠券平台排名如下 NO.1 什么值得买品牌指数: 10.0什么值得买是一群极度热爱网购的剁手党共同建立的网站。...在什么值得买还有大量的网友原创内容,他们擅长记录生活

    NO.1 什么值得买品牌指数: 10.0什么值得买是一群极度热爱网购的剁手党共同建立的网站。 什么值得买不卖货,但作为第三方导购平台,把来自不同电商的优惠商品信息汇总起来。促销活动、打折商品、限量抢购等信息,在什么值得买都能看得到。双十一抢购、黑五海淘节更是什么值得买的拿手好戏,超多优惠信息一次性满足你。同时,什么值得买还提供大量购物攻略,手把手带您一起抢神价、捡白菜,享受低价。在什么值得买还有大量的网友原创内容,他们擅长记录生活,也乐于辛辣点评,更还有一些领域的专家达人。 什么值得买好物频道,旗下包含:好物榜单、商品百科、消费众测、新锐品牌四个独立子频道,致力于搭建决策性的消费决策内容平台,努力通过各子频道内容,帮助您迅速选购心仪商品及品牌。 “好物榜单”,是“什么值得买”旗下基于商品百科衍生的新型内容形态,包含:品类选购榜单及销量排行榜单。内容类型涉及:品牌新品、时效热点、选购参考、购物场景、新奇好物等多种内容类型,专注于以轻量化/结构化内容形态,更好的帮您迅速选购心仪商品及品牌。 “商品百科”,是由“什么值得买”用户分享、品类共建的优质商品百科全书。收录为值友们听过、见过或者使用过的,愿意向更多人推荐的优质商品。致力于当您选购商品时,通过搜索或分类、标签筛选,帮您迅速找到心仪商品。 “新锐品牌”,是“什么值得买”旗下着眼于建立连接用户与新品牌的平台,专注从新品牌维度推荐商品和服务。以工具和内容的形式帮助用户迅速定位自己所需的新品牌,同时帮助新品牌更好地用商品和服务维护自己的目标用户。

    NO.2 小红书品牌指数: 9.8成立于2013年,颇具人气的年轻生活方式分享平台,专注于让用户通过短视频/图文等形式标记生活点滴的创新型互联网公司 小红书是年轻人的生活方式平台,由毛文超和瞿芳于2013年在上海创立。 小红书以“Inspire Lives 分享和发现世界的精彩”为使命,用户可以通过短视频、图文等形式记录生活点滴,分享生活方式,并基于兴趣形成互动。截至到2019年10月,小红书月活跃用户数已经过亿,其中70%用户是90后,并持续迅速增长。 小红书社区目前内容覆盖时尚、个护、彩妆、美食、旅行、娱乐、读书、健身、母婴等各个生活方式领域,每天产生超过70亿次的笔记曝光,其中超过95%为UGC内容。 小红书企业号部门围绕“企业号”这一核心产品,整合公司从社区营销一直到交易闭环的资源,更好地连接消费者和品牌,帮助品牌在小红书完成一站式闭环营销,提供全链条服务。 小红书福利社是小红书的自营电商平台,在小红书福利社,用户可以一键购买来自全世界的优质美妆、时尚、家电、零食商品。

    NO.3 高省品牌指数: 9.6高省app是杭州长孚科技有限公司旗下 [1] 的一款电商导购应用,为用户打造一个电商购物优惠平台,用户可以在这个App中领取主流商城的商品隐藏优惠券以及获得返利。基于第三方电商平台海量数据挖掘与分析,“高省”APP通过内容制作、分享等方式,为消费者打通吃喝玩乐购全场景全业态 [1] ,让消费者省钱省时省力,为平台和品牌方导流创造收入 [1] ,拓展了商家新的销售渠道。 [1]高省app逐渐构筑起了集各大主流电商平台,外卖平台,旅游、票务、出行、加油等高频生活服务全场景的线上生活商城。高省功能编辑 语音【高】用户可以在这个App中获取高佣返利。【省】用户可以在这个App中领取主流商城的商品隐藏优惠券。【多】优惠券覆盖了线上线下多个平台,内容包含衣食住行各大消费品类。 [1]

    NO.4 一淘品牌指数: 9.4阿里巴巴集团旗下促销类导购平台,立足淘宝网/天猫/飞猪等阿里巴巴集团的丰富商品基础,通过返利/优惠券/红包等丰富的促销利益点,为用户提供高性价比的品牌好货。

    NO.5 识货品牌指数: 9.1虎扑旗下专门做运动潮流购物平台的网站,覆盖国内外主流购物商城折扣商品导购,同时网罗全网值得买的好货 识货是上海识致信息科技有限责任公司旗下专门做运动潮流购物平台的网站,成立于2012年6月,成立初期主要为用户提供折扣、正品运动鞋商品导购,对于市场上热门的运动鞋都会进行评测,把真实的运动鞋体验传递给爱好者,经过2年多的发展,识货除了提供运动鞋导购,还提供包括生活电器、服装、食品、家居等全品类优惠信息导购,2014年3月,随着识货海淘频道的上线,识货把海外主流商城的优质廉价商品也开始推荐给网购用户,并且为没有条件海淘的用户提供免费的代下单服务,深受欢迎。至此,识货全面覆盖国内外主流购物商城折扣商品导购。 识货除了自身运营发布新鲜、全面的商品优惠信息,期间还开发了发现好货频道,喜欢网购的朋友遇到值得买的好货可以在此进行爆料、分享,识货会对网友爆料进行核实、修正,通过的爆料会在发现好货进行展现,同时对于识货未能发现的其他超值好货给予首页推荐等更多方式的展现。 识货在成立之初,商品优惠信息主要通过PC端网页进行发布,为满足更多用户的需求,识货还开发了移动端方便喜欢使用手机购物的网友,在2014年4月份,识货还开发了识货app并上线,至此,识货拥有PC端/移动端等全部方式为喜爱折扣商品的网友提供更多的购物环境选择。

    NO.6 返利网品牌指数: 8.9成立于2006年,国内知名全场景导购平台,为消费者提供全景式消费服务,涵盖了购物/旅行/本地生活/票务/出行/学习等诸多消费场景返利成立于2006年,是国内优质的全场景导购平台,拥有累计注册人数超过2.4亿人次,年活跃用户超过4000万,影响6亿中国消费者,为消费者提供360°全景式消费服务,涵盖了购物、旅行、本地生活、票务、出行、学习等诸多消费场景。返利已与国内超过400家商城&平台、逾5万家品牌商户合作,几乎涵盖了全球知名电商,包括天猫、淘宝、京东、苏宁易购、携程、华为商城、爱彼迎、亚马逊、聚美优品、苹果官网等知名电商平台,覆盖逾百万家本地生活线下门店。

    NO.7 粉象生活品牌指数: 8.8

    粉象生活是由杭州粉象家科技有限公司旗下的社交电商平台,它是一款全网全品类的综合优惠导购分享型APP,粉象生活是邀请码拉人机制,里面有各种等级机制,不同等级返钱不一样(邀请码必填否则无法注册,邀请码百度一下就有了),喜欢这种模式的建议使用。

    NO.8 花生日记品牌指数: 8.6

    花生日记的模式和上面粉象生活的模式很像,是广州花生日记网络科技有限公司于2017年开发的返利app,app,是以“少花钱,多生钱”的理念,为消费者打造出一站式“领券优惠、分享获利”的社交电商导购平台,买家通过APP搜索电商平台的优惠券,达到购物省钱的目的,有很多用户和粉丝,推荐喜欢粉象的用户下载比较一下选择哪款。

    NO.9 淘粉吧品牌指数: 8.4国内知名返利导购网站,主推超高返利商品,为用户提供优质体验/返利/购物参考的专业化导购平台 淘粉吧隶属于杭州淘粉吧网络技术股份有限公司,成立于2011年6月。从公司成立到如今,一直以优质的体验和高额的返利,如首开创先行垫付、超高返利模式优于返利行业,拥有几千万的用户,仅客户端日活跃用户就超过100万级别。 淘粉吧的合作伙伴涵盖了所有专业电商网站。当用户通过淘粉吧去对应的商家网站下单购物,商家会为用户的订单支付给淘粉吧一笔营销费用,淘粉吧把绝大部分费用以返利的形式返还给用户,这就是返利的来源。目前淘粉吧主推超高返利商品,直接与电商平台知名品牌商家合作,给用户提供超高额的返利,限时限量,每日10点上新。

    NO.10 卷皮品牌指数: 8.1诞生于2012年,专注于服务消费者日常生活所需的平价电商平台,主营业务为通过互联网在线销售服饰/居家/母婴/数码/鞋包/美妆等商品 卷皮是国内平价电商平台,专注服务更广泛群体的日常生活所需。以为用户提供美好的生活体验为使命,潜心研究用户生活质量,倡导经济实用主义美学,致力于成为品质消费的行业领军者。 卷皮诞生于2012年9月,是武汉奇米网络科技有限公司创办的B2C电子商务平台,总部设在武汉,是一家服务消费者日常生活所需的平价电商平台,先后获得由汉理资本、纽信创投、赛富亚洲、天图资本、招银国际资本,浙江金控的投资。主营业务为通过互联网在线销售服饰、居家、母婴、数码、鞋包、美妆等商品。 以用户数量等为衡量标准,我们在国内的电商平台企业中,仅次于阿里系、京东、唯品会,进入国内一线电商的阵营。 凭借创新的平价零售模式和精细化运营,卷皮成为中国发展速度较快的移动电商之一。目前公司规模已经超过千人,年成交规模数十亿,用户规模突破1亿。并获得业内和资本市场认可,目前公司已完成三轮融资,累计融资近10亿,主要投资方包括天图资本、赛富、招银国际等投资机构。 经过短短几年的专注耕耘,凭借独特的产品定位、创新商业模式和有机的人才建设,目前,卷皮年成交额已突破百亿,用户超过1亿。

    展开全文
  • 开放平台设计方案与实践

    千次阅读 热门讨论 2021-05-13 00:29:58
    基于这个痛点,我们有必要打造一套开放平台来管理各个 api 的调用情况。 二、开放平台设计 我们先从整体的功能需求来分析,主要有以下几点: 开发者身份注册与数据权限范围授权 开发者获取相关资料(接口文档、使用...

    欢迎大家关注我的微信公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。

    一、背景

    随着业务的发展,越来越多的系统需要数据往来。那对外提供的接口也越来越多,而且各个接口散落在不同的项目中被调用,多了的话排查问题困难且混乱。基于这个痛点,我们有必要打造一套开放平台来管理各个 api 的调用情况。

    二、开放平台设计

    我们先从整体的功能需求来分析,主要有以下几点:

    • 开发者身份注册与数据权限范围授权
    • 开发者获取相关资料(接口文档、使用说明、对接人联系方式等)
    • 平台方接入管理,申请审核流程、服务配置、服务管理、参数配置等
    • 平台方运营管理,业务交易管理及统计报表分析
    • 安全层面需求,加密、应用秘钥、应用接口权限控制、访问黑白名单、字段脱敏还原等
    • 性能方面要求,客户端缓存、服务端缓存、缓存等

    在这里插入图片描述
    这里老周给出自己的一个架构,大家可以参考下:

    在这里插入图片描述

    上面的设计方案更多的是针对比较大型的公司,想要把整个开平的能力建设完善。但市场上更多的是中小型公司,它们没有太多的人力去开发与建设这么全面的开放平台。

    那如果是中小型公司,那它们的开放平台如何不费很大精力去实现呢?不管中小型还是大型公司的开放平台,上面说的那个图中其它部分可以省略,但安全机制是必需的,也就是架构图中的统一鉴权。试想一下,作为提供给第三方调用接口的开放平台,如果安全机制不能保障,那外部谁都可以来调用你们公司的内部资源,危害可想而知。

    老周下面就来针对不同的业务场景来给出相应的开放平台安全机制的保障,也就是根据不同类型的网站给出相对应的开放平台设计方案。

    三、小型网站

    3.1 基于 session 的登录认证

    在传统的用户登录认证中,因为 http 是无状态的,所以都是采用 session 方式。用户登录成功,服务端会保存一个 session,当然会给客户端一个 sessionId,客户端会把 sessionId 保存在 cookie 中,每次请求都会携带这个 sessionId。服务器收到 sessionId,找到前期保存的数据,由此得知用户的身份。

    在这里插入图片描述
    对于小型网站,特别是单机系统,基于 session 的登录认证方案已经够用了,而且简单高效。

    四、中型网站

    随着用户量的增多,上面基于 cookie + session 的这种模式缺点就显现出来了,这种模式通常是保存在内存中,而且服务从单服务到多服务会面临 session 共享问题,开销也随即越来越大。

    那中型网站的安全认证机制是啥呢?接下来 JWT(JSON Web Token) 即将登场,关于 JWT 的概念与原理,老周这里觉得还是有必要说一下。

    4.1 JWT 的概念

    4.1.1 什么是 JWT?

    JWT 是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递 json 对象,传递的信息经过数字签名可以被验证和信任。JWT 可以使用 HMAC 算法或使用 RSA的公钥/私钥对来签名,防止被篡改。

    说白了 JWT 就是一套基于 token 的身份认证的方案,可以保证安全传输的前提下传送一些基本的信息,以减轻对外部存储的依赖,减少了分布式组件的依赖,减少了硬件的资源。

    可实现无状态、分布式的 Web 应用授权,JWT 的安全特性保证了 token 的不可伪造和不可篡改。

    本质上是一个独立的身份验证令牌,可以包含用户标识、用户角色和权限等信息,以及您可以存储任何其他信息(自包含)。任何人都可以轻松读取和解析,并使用密钥来验证真实性。

    4.1.2 JWT 令牌结构

    JWT 令牌由三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz

    • Header
      头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA),例如:

      {
      	"alg": "HS256", 
      	"typ": "JWT"
      }
      

      将上边的内容使用 Base64Url 编码,得到一个字符串就是 JWT 令牌的第一部分。

    • Payload
      第二部分是负载,内容也是一个 json 对象,它是存放有效信息的地方,它可以存放 jwt 提供的现成字段,比如:iss(签发者),exp(过期时间戳),sub(面向的用户)等,也可自定义字段。 此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。 最后将第二部分负载使用 Base64Url 编码,得到一个字符串就是 JWT 令牌的第二部分。 一个例子:

      {
      	"sub": "1234567890", 
      	"name": "微信公众号【老周料架构】", 
      	"iat": 1516239022
      }
      
    • Signature
      第三部分是签名,此部分用于防止 jwt 内容被篡改。 这个部分使用 base64url 将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用 header 中声明签名算法进行签名。
      secret:签名所使用的密钥。

      HMACSHA256 ( 
      	base64UrlEncode(header) + "." + base64UrlEncode(payload), secret
      )
      

      验签过程描述:获取 token 值,读取 Header 部分并 Base64 解码,得到签名算法。根据以上方法算出签名,如果签名信息不一致,说明是非法的。

    4.2 JWT 的流程

    在这里插入图片描述
    4.3 JWT 代码案例

    如果你们公司有第三方应用接入的开放平台,那可以在里面走相应的接入流程得到 appId 和 appSecret。如果没有的话,那可以简单点与第三方约定相应的 appId 和 appSecret。老周这里假设你们已经约定好了,我这里直接放在请求头里来获取 token,还有其它的方式,比如放在请求参数或者 cookie 里。

    4.3.1 maven 依赖

    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.4.1</version>
    </dependency>
    

    4.3.2 JWTUtil 工具类

    public class JWTUtil {
        private static String SECRETE = "default_secrete";
        private static String APP_ID = "zhifubao";
        private static String APP_SECRETE = "123abc";
    
        /**
         * 传入 appId、appSecret 进行验证
         * @param appId 应用id
         * @param appSecret 应用密钥
         * @return 返回一个加密 JWT token
         */
        public static String getToken(String appId, String appSecret) {
            String token = JWT.create()
                    // 存放 payload 数据
                    .withClaim("appId", appId)
                    .withClaim("appSecret", appSecret)
                    // 使用 SECRETE 对称加密生成 signature
                    .sign(Algorithm.HMAC256(SECRETE));
            return token;
        }
    
        /**
         * 验证 token
         * @param token
         * @return
         */
        public static boolean verifyToken(String token) {
            HashMap<String, String> map = new HashMap<>();
            // 通过 SECRETE 和相同的对称加密算法反加密
            DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SECRETE))
                    .build().verify(token);
            // 获得你储存的 payload 信息
            String appId = jwt.getClaim("appId").asString();
            String appSecret = jwt.getClaim("appSecret").asString();
            if (APP_ID.equals(appId) && APP_SECRETE.equals(appSecret)) {
                return true;
            }
            return false;
        }
    }
    

    4.3.3 JWTController 类

    @RestController
    public class JWTController {
        @RequestMapping("/getToken")
        public String getToken(@RequestHeader("appId") String appId, @RequestHeader("appSecret") String appSecret) {
            return JWTUtil.getToken(appId, appSecret);
        }
    }
    

    4.3.4 测试

    在这里插入图片描述

    拓展:这个私钥 secrete 是固定的,为了加强安全,你甚至可以使用动态的 secrete 私钥,
    例如:动态私钥 = 静态私钥 + 用户的 ip,这样即使别人得到了用户的 token,也会因为 ip 不一致而访问失败。

    拿到了应用资源服务器的 token 令牌了,那我们拿这个令牌去访问相应的资源看看。

    @RequestMapping("/getResource")
    public String getResource(String resourceId) {
        return resourceId + " 资源获取成功";
    }
    

    简单模拟一个请求,直接返回该资源获取成功。我们接下来就用 postman 工具来模拟一下这个资源服务器的这个接口请求。

    在这里插入图片描述
    认证失败了,这是因为我们没有在请求头里填刚刚获取的 token。我们把通过调用 getToken 接口获取的 token 值放在在请求头,然后认证通过,获取到了资源服务器的资源。

    在这里插入图片描述
    4.3.5 继续追问

    这里你有可能问了,老周,这里咋就带上 token 在请求头就可以获取到了资源服务器的资源啊。

    我把代码贴出来,你一看就知道了。

    这里写了一个 token 的拦截器,对请求头的 token 进行验签,通过才放行。

    @Component
    public class TokenInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String token = request.getHeader("token");
            if (token != null) {
                boolean result = JWTUtil.verifyToken(token);
                if (result) {
                    System.out.println("通过拦截器");
                    return true;
                }
            }
    
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            try{
                response.getWriter().append("认证失败,无效的token令牌!");
                System.out.println("认证失败,无效的token令牌!");
            } catch (Exception e) {
                e.printStackTrace();
                response.sendError(500);
                return false;
            }
            return false;
        }
    }
    

    这里有个拦截器配置类,把需要拦截的 api 路径放进来,然后会对某个 api 进行细粒度的管控。

    @Configuration
    public class IntercepterConfig implements WebMvcConfigurer {
        private TokenInterceptor tokenInterceptor;
    
        public IntercepterConfig(TokenInterceptor tokenInterceptor){
            this.tokenInterceptor = tokenInterceptor;
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            List<String> excludePath = new ArrayList<>();
            excludePath.add("/getResource/");
            excludePath.add("/static/**");  //静态资源
            registry.addInterceptor(tokenInterceptor)
                    .addPathPatterns("/**")
                    .excludePathPatterns(excludePath);
            WebMvcConfigurer.super.addInterceptors(registry);
        }
    }
    

    这就实现中型网站安全认证机制了,细心的读者可能会发现,这个 token 是固定的,会存在一些不安全。是的,我上面也说了,可以用动态的 secrete 私钥或者 token 过期机制来继续保证更高的安全性。

    五、大型网站

    大型网站的话,针对中型网站的方案就不太可行了,为什么呢?由于大型网站的请求流量很大,而 token 由于自包含信息,因此一般数据量较大,而且每次请求都需要传递,因此比较占带宽。另外,token 的签名验签操作也会给 cpu 带来额外的处理负担。可以采用微服务统一认证方案 Spring Cloud OAuth2,那什么情况下需要使用 OAuth2?

    • 第三方授权登录的场景:比如,我们经常登录一些网站或者应用的时候,可以选择使用第三方授权登录的方式,比如:微信授权登录、QQ授权登录、微博授权登录等,这是典型的 OAuth2 使用场景。
    • 单点登录的场景:如果项目中有很多微服务或者公司内部有很多服务,可以专⻔做一个认证中心(充当 认证平台⻆色),所有的服务都要到这个认证中心做认证,只做一次登录,就可以在多个授权范围内的服务中自由串行。

    5.1 OAuth2 构建微服务统一认证服务思路

    在这里插入图片描述
    注意:在我们统一认证的场景中,Resource Server 其实就是我们的各种受保护的微服务,微服务中的 各种 API 访问接口就是资源,发起 http 请求的浏览器就是 Client 客户端(对应为第三方应用)。

    5.1.1 搭建认证服务器(Authorization Server)

    5.1.1.1 maven 依赖文件

    在这里插入图片描述
    5.1.1.2 application.yml 文件

    在这里插入图片描述
    5.1.1.3 OauthServerApplication9999 启动类
    在这里插入图片描述
    5.1.1.4 认证服务器配置类

    在这里插入图片描述
    5.1.1.5 认证服务器安全配置类

    在这里插入图片描述
    5.1.1.6 测试

    5.1.1.6.1 获取 token

    http://localhost:9999/oauth/token?client_secret=abcxyz&grant_type=password&username=admin&password=123456&client_id=client_riemann

    endpoint:/oauth/token

    获取token携带的参数
    client_id:客户端id
    client_secret:客户单密码
    grant_type:指定使用哪种颁发类型,password
    username:用户名
    password:密码

    在这里插入图片描述
    5.1.1.6.2 校验 token

    http://localhost:9999/oauth/check_token?token=28317df7-4036-4bbb-8bb3-12f71fa07802

    在这里插入图片描述
    如果出现以上页面,表明 token 过期了,设置的是 20s。所以要在 20s 以内校验才会生效。

    下面才是 token 校验成功的效果:

    在这里插入图片描述
    5.1.1.6.3 刷新 token

    http://localhost:9999/oauth/token?grant_type=refresh_token&client_id=client_riemann&client_secret=abcxyz&refresh_token=68582d02-3a1d-4c31-ae22-ac7e84824d0d

    在这里插入图片描述
    5.1.2 搭建资源服务器(希望访问被认证的微服务)

    5.1.2.1 资源服务 Resource Server 配置类

    在这里插入图片描述
    5.1.2.2 测试

    在这里插入图片描述
    在这里插入图片描述
    此测试结果也印证了代码的效果

    在这里插入图片描述
    我们加上带上token测下看看:

    在这里插入图片描述
    5.2 OAuth2 统一认证服务思考

    • 当我们第一次登陆之后,认证服务器颁发 token 并将其存储在认证服务器中,后期我们 访问资源服务器时会携带 token,资源服务器会请求认证服务器验证 token 有效性,如果资源服务器有很多,那么认证服务器压力会很大。
    • 另外,资源服务器向认证服务器 check_token,获取的也是用户信息 UserInfo,能否把用户信息存储到令牌中,让客户端一直持有这个令牌,令牌的验证也在资源服务器进行,这样避免和认证服务器频繁的交互。
    • 我们可以考虑使用 JWT 进行改造,使用 JWT 机制之后资源服务器不需要访问认证服务器。

    5.3 JWT 改造统一认证授权中心的令牌存储机制

    JWT 在上面中型网站那一节说过了,这里就不重复说了,老周直接上代码了。

    5.3.1 认证服务器端 JWT 改造(改造主配置类)

    在这里插入图片描述

    5.3.2 修改 JWT 令牌服务方法

    在这里插入图片描述
    5.3.3 认证服务器端测试

    在这里插入图片描述
    可以看出,使用 jwt 令牌生成的 access_token 和上一篇的不一样。

    我们用这个网站:https://jwt.io/#encoded-jwt 把该 access_token 进行解码,解码如下:

    在这里插入图片描述
    其他两个验证 token、刷新 token 跟上一篇类似。

    5.3.4 资源服务器校验 JWT 令牌

    不需要和远程认证服务器交互,添加本地 tokenStore。

    在这里插入图片描述
    5.3.5 源服务器端测试

    在这里插入图片描述
    在这里插入图片描述
    这样就完成了资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权。

    六、总结

    老周首先从开放平台的整体功能设计来分析了有如下几个要点:开发者认证、开放平台内部管理系统、安全机制以及性能。

    但考虑很多公司它们没有太多的人力去开发与建设这么全面的开放平台,故抓住其中的最核心的一点,那就是安全机制。

    针对于安全机制来说,不同类型的网站有不同的安全机制保障。

    • 小型网站:基于 session 的登录认证,在小型网站特别是单机系统,这种方案够用了,而且简单高效;
    • 中型网站:到了中型网站,服务肯定是分布式部署的,这个时候小型网站中基于 session 的登录认证方案的缺点就暴露出来了。每个应用服务都需要在 session 中存储用户身份信息,通过负载均衡将本地的请求分配到另一个应用服务需要将 session 信息带过去,否则会重新认证。我们还要通过 session 共享、session 黏贴等方案来解决。从而引入了第三方分布式组件,比如 redis,增加了系统的复杂性。并且 session 方案还有另一个缺点,比如基于 cookie,移动端不能有效使用等。所以中型网站的话基于 JWT 的 token 认证机制,服务端不用存储认证数据,易维护扩展性强,客户端可以把 token 存在任意地方,并且可以实现 web 和 app 统一认证机制。
    • 大型网站:到了大型网站,请求量也随之暴涨,中型网站的 token 认证机制的缺点也逐步暴露出来了,token 由于自包含信息,因此 一般数据量较大,而且每次请求都需要传递,因此比较占带宽。另外,token 的签名验签操作也会给 cpu 带来额外的处理负担。这个时候得采用微服务统一认证方案 Spring Cloud OAuth2,后面我们又对 OAuth2 进行了一些优化,因为大型网站的开平请求流量会很大,资源服务器会请求认证服务器验证 token 有效性,那么认证服务器压力会很大。另外,资源服务器向认证服务器 check_token,获取的也是用户信息 UserInfo,能否把用户信息存储到令牌中,让客户端一直持有这个令牌,令牌的验证也在资源服务器进行,这样避免和认证服务器频繁的交互。所以我们后续使用 JWT 进行改造,使用 JWT 机制之后资源服务器不需要访问认证服务器。性能以及安全机制都得到了有力保障。

    看完希望对你有所帮助,有帮助的话,请不要吝啬你的点赞、评论、收藏,毕竟原创不易。 好了,我们下期再见。

    展开全文
  • OpenStack云平台的管理

    千次阅读 2021-11-26 20:50:23
    软硬件要求:最少16G内存,至少2CPU ...2.是一个开源的云计算管理平台 3.Apache许可证为授权 图解 openstack组件 1.Horizon组件: --为openstack服务的web控制面板,它可以管理实例,镜像,创建密钥令...
  • Power平台迁移指南

    千次阅读 2021-12-01 11:20:20
    在使用Power平台过程中,可能会遇到现有X86平台的应用程序无法在Power平台中直接运行的问题,这是由Power平台与X86平台的架构差异造成的,因此需要通过软件迁移对相关应用进行基于Power平台的适配。迁移工作首先是...
  • 飞瓜数据(B站版)独家推出《2021年双十一报告(B站平台)》,从B站全行业大盘、双十一用户画像、品牌洞察和品牌营销案例,分析B站双十一多维度数据,为品牌和内容创作者前瞻B站营销的发展趋势与机遇提供客观的数据...
  • 国家中小学网络云平台登录入口_国家中小学网络云平台网,国家中小学网络云平台资源包括防疫教育、品德教育、专题教育、课程学习、电子教材、影视教育及有关地方教育资源。教育部利用国家中小学网络云平台和中国教育...
  • 福建公共交易平台portal-sign

    千次阅读 2021-11-25 13:45:23
    福建省公共资源交易电子公共服务平台-headers中的加密参数portal-sign的分析。 AES加密之前有写过,本篇不再讲解了,可以去看 《福建公共资源电子服务...声明:文章内容仅供参考学习,如有侵权请联系作者进行删除 Js
  • 使用讯飞平台进行了多次测试,在仅使用网页端的情况下,关于切屏有如下要素。浏览器基于chrome内核。1、切屏逻辑:首先鼠标得在答题界面内,点击网页标签页以外的地方,如其他网页标签页、浏览器外的位置,随后又点击...
  • 算力卡 算力卡说明 算力卡获取 邀请码验证 以下有关文字内容部分源于官方文档,所有内容以官方为准 算力卡说明 AI Studio 单机项目配备工业级NVIDIA Tesla V100 GPU资源. NVIDIA Tesla V100 是当今市场上加速人工...
  • 数字乡村的建设内容

    千次阅读 2021-06-17 00:54:51
    总体来说,数字乡村建设涵盖的内容可归纳为乡村信息基础设施、乡村能力支撑平台、乡村产业数字化、乡村治理数字化、乡村民生数字化五个方面。 1、乡村信息基础设施 乡村信息基础设施是数字乡村的基石,包括网络基础...
  • 各大游戏售卖平台

    万次阅读 2020-12-23 01:42:38
    WeGame之所以把 WeGame...WeGame 目前上架了 19 款单机内容,而大多也是以国内作品/独立游戏为主,诸如《小三角大英雄》《古剑奇谭》《小三角大英雄》《饥荒》《深海迷航》等等。而在 WeGame 商店中其实的占比较大的...
  • 校园一体化平台

    千次阅读 2021-07-25 16:49:44
    校园一体化平台策划书 目录 一、 项目情况介绍 3 1.1项目意义 3 1.2项目背景 3 1.3项目内容 4 二、 需求分析 6 2.1用户需求 6 2.2性能需求 6 2. 3可行性分析 7 三、 市场分析 7 四、 竞争分析和风险分析 8 4.1竞争...
  • java三大技术平台是什么

    千次阅读 2021-02-12 11:46:54
    JAVA分为三大技术平台,如下:Java SE( Java Platform Standard Edition)标准版,是为开发普通桌面和商务应用程序提供的解决方案。JavaSE是三个平台中最核心的部分, JavaEe和 JavaME都是从 JavaSE的基础上发展而来...
  • 本地搭建乌云漏洞平台

    千次阅读 2021-10-19 16:09:36
    将下载的乌云数据库文件、网页等内容全部下载下来,最终内容如下 phpstudy下载:https://www.xp.cn/download.html 下载phpstudy,目前最新版本是V8.1,直接安装就可以。 环境搭建 创建网站 首先创建一个自己喜欢的...
  • 各大自媒体平台收益排名?

    千次阅读 2020-12-29 08:59:40
    下面速链吧就给大家捋一捋这些主流自媒体平台收益排名:一、百家号这可是互联网三巨头之一百度旗下的一个自媒体平台,百家号的收益最高无疑,是现在已知自媒体平台中单价最高的,用户发布文章就会被推送到百度、手机...
  • 一文读懂CIM平台的定义和架构

    千次阅读 2021-05-16 00:53:56
    CIM平台示意图 从建设路径上看: CIM平台可以基于智慧城市已建的时空大数据平台扩展,后者为CIM在三维空间和时间交织构成的四维环境中,提供了时空基础服务,通过应用虚拟现实、大数据、区块链等技术,拓展时空...
  • “ 目前市面上主营短信验证码业务的平台有哪几家、手机验证码平台哪个好,它们提供哪些短信验证码服务,短信发送的速度、送达率和稳定性等技术性能如何,短信收费价格多少钱。今天通过评测阿里云、梦网云通讯、容联...
  • 购物直播卡成定格,最新款球鞋被抢光? 游戏卡顿,来不及放大招就被秒?...AgileCDN全新内容分发和网络加速SaaS平台,搭载了AWS CloudFront强悍性能,CDN资源储备遍布全球90个重点城市,拥有的260+全自有自建超级POP
  • 我在业余时间构建了一个租房平台,采用springboot微服务的架构模式,同时结合服务化思想进行代码实践,但是由于存在很多重复且低效的变更导致业余时间对这个租房平台的进度产生影响。作为开发人员长期维护一个业余...
  • 福建公共服务平台-AES解密

    千次阅读 热门讨论 2021-11-25 12:43:36
    福建省公共资源交易电子公共服务平台-响应内容的AES解密分析。 有群友在问这个网站数据的加密类型,我分析了一下该网站的数据加密,正好写一篇案例。 案例网址:https://ggzyfw.fj.gov.cn/ 文章目录逻辑分析Base64...
  • 在SAP云平台上部署和运行Docker应用 使用SAP云平台Mobile Service开发移动应用 SAP云平台上的Low Code Development(低代码开发)解决方案 SAP智能机器人流程自动化解决方案 在SAP云平台ABAP编程环境上编写第一段ABAP...
  • 说到短信验证码平台,相信很多人都不了解什么是短信验证码平台,简单的来说,就是一个可以发送短信验证码、短信通知和营销短信的平台。那么,目前可以用的短信验证码平台有哪些呢?下面就让小杜来跟大家详细的介绍...
  • 遵循AUTOSARAdaptive R19-11规范,使用C++11语言和POSIX操作系统,除实现诸如诊断(UDS和DOIP)、面向服务通信(SOMEIP)、网络管理、数据持久化等基本功能外,还实现了执行管理、平台健康管理、状态管理、配置及...
  • 小米大数据平台OLAP架构 演进 一、数据仓库 1、离线数据仓库的架构 数据仓库一般架构 分析型系统进行联机数据分析,一般的数据来源是数据仓库,而数据仓库的数据来源为可操作型系统,可操作型 系统的数据来源...
  • 数据分析——DAU下降/上升原因分析

    千次阅读 2021-03-05 14:48:47
    本文是作为新手数据分析师对“DAU下降”问题进行的思考整理,仅作记录,欢迎讨论。 1.
  • 简单介绍在线OTA几款平台

    千次阅读 2021-03-30 10:09:29
    看好在线旅游平台——飞猪,携程,途牛,美团,马蜂窝,去哪儿旅行,同程(艺龙),马蜂窝,去哪儿旅行,京东旅行和驴妈妈。 在线旅游(OTA,全称为Online Travel Agency),是旅游电子商务行业的专业词语。指...
  • 安全教育平台登录失败是怎么回事 解决方法2020-12-18 16:22:21 来源:网络整理扫码可以:1.在手机上浏览2.分享给微信好友或朋友圈摘要:有很多的同学们反映说安全教育平台一直登录不上,但是自己账号和密码都是对的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,449,707
精华内容 579,882
关键字:

内容平台