目录

一、无状态登录原理

1.1 什么是有状态

1.2 什么是无状态

1.3 如何实现无状态

1.4 JWT

1.4.1 简介

1.4.2 数据格式

1.4.3 JWT交互流程

1.4.4 非对称加密

1.5 结合Zuul的鉴权流程

1.5.1 没有RSA加密时

1.5.2 结合RSA的鉴权

二、授权中心

2.1 创建授权中心

2.1.1 创建父module

2.1.2 通用module

2.1.3 授权服务

2.2 JWT工具类

2.3 测试工具类

2.4 编写登录授权接口

2.4.1 生成公钥和私钥

2.4.2 Controller

2.4.3 CookieUtils

2.4.4 UserClient

2.4.5 Service

2.4.6 项目结构

2.4.7 测试

2.5 登录页面

2.6 解决cookie写入问题

2.6.1 问题分析

2.6.2 跟踪CookieUtils

2.6.3 解决host地址的变化

2.6.4 再次测试

2.6.5 Zuul的敏感头过滤

2.6.6 最后的测试


一、无状态登录原理

1.1 什么是有状态

有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。

例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,就能识别到对应session,从而找到用户的信息。

缺点是什么?

  • 服务端保存大量数据,增加服务端压力

  • 服务端保存用户状态,无法进行水平扩展

  • 客户端请求依赖服务端,多次请求必须访问同一台服务器

1.2 什么是无状态

微服务集群中的每个服务,对外提供的都是Rest风格的接口。而Rest风格的一个最重要的规范就是:服务的无状态性,即:

  • 服务端不保存任何客户端请求者信息

  • 客户端的每次请求必须具备自描述信息,通过这些信息识别客户端身份

带来的好处是什么呢?

  • 客户端请求不依赖服务端的信息,任何多次请求不需要必须访问到同一台服务

  • 服务端的集群和状态对客户端透明

  • 服务端可以任意的迁移和伸缩

  • 减小服务端存储压力

1.3 如何实现无状态

无状态登录的流程:

  • 当客户端第一次请求服务时,服务端对用户进行信息认证(登录)

  • 认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证

  • 以后每次请求,客户端都携带认证的token

  • 服务端对token进行解密,判断是否有效。

整个登录过程中,最关键的点是什么?

token的安全性

token是识别客户端身份的唯一标示,如果加密不够严密,被人伪造那就完蛋了。

采用何种方式加密才是安全可靠的呢?

采用JWT + RSA非对称加密

1.4 JWT

1.4.1 简介

JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;官网:https://jwt.io

GitHub上jwt的java客户端:https://github.com/jwtk/jjwt

1.4.2 数据格式

JWT包含三部分数据:

  • Header:头部,通常头部有两部分信息:

    对头部进行base64加密(可解密),得到第一部分数据

    • 声明类型,这里是JWT

    • 加密算法,自定义

  • Payload:载荷,就是有效数据,一般包含下面信息:

    这部分也会采用base64加密,得到第二部分数据

    • 用户身份信息(注意,这里因为采用base64加密,可解密,因此不要存放敏感信息)

    • 注册声明:如token的签发时间,过期时间,签发人等

  • Signature:签名,是整个数据的认证信息。一般根据前两步的数据,再加上服务的的密钥(secret)(不要泄漏,最好周期性更换),通过加密算法生成。用于验证整个数据完整和可靠性

生成的数据格式:

1.4.3 JWT交互流程

流程图:

步骤翻译:

  • 1、用户登录

  • 2、服务的认证,通过后根据secret生成token

  • 3、将生成的token返回给浏览器

  • 4、用户每次请求携带token

  • 5、服务端利用公钥解读jwt签名,判断签名有效后,从Payload中获取用户信息

  • 6、处理请求,返回响应结果

因为JWT签发的token中已经包含了用户的身份信息,并且每次请求都会携带,这样服务的就无需保存用户信息,甚至无需去数据库查询,完全符合了Rest的无状态规范。

1.4.4 非对称加密

加密技术是对信息进行编码和解码的技术,编码是把原来可读信息(又称明文)译成代码形式(又称密文),其逆过程就是解码(解密),加密技术的要点是加密算法,加密算法可以分为三类:

  • 对称加密,如AES

    • 基本原理:将明文分成N个组,然后使用密钥对各个组进行加密,形成各自的密文,最后把所有的分组密文进行合并,形成最终的密文。

    • 优势:算法公开、计算量小、加密速度快、加密效率高

    • 缺陷:双方都使用同样密钥,安全性得不到保证

  • 非对称加密,如RSA

    • 基本原理:同时生成两把密钥:私钥和公钥,私钥隐秘保存,公钥可以下发给信任客户端

      • 私钥加密,持有私钥或公钥才可以解密

      • 公钥加密,持有私钥才可解密

    • 优点:安全,难以破解

    • 缺点:算法比较耗时

  • 不可逆加密,如MD5,SHA

    • 基本原理:加密过程中不需要使用密钥,输入明文后由系统直接经过加密算法处理成密文,这种加密后的数据是无法被解密的,无法根据密文推算出明文。

1.5 结合Zuul的鉴权流程

需要注意的是:secret是签名的关键,因此一定要保密,所以放到鉴权中心保存,其它任何服务中都不能获取secret。

1.5.1 没有RSA加密时

在微服务架构中,可以把服务的鉴权操作放到网关中,将未通过鉴权的请求直接拦截,如图:

  • 1、用户请求登录

  • 2、Zuul将请求转发到授权中心,请求授权

  • 3、授权中心校验完成,颁发JWT凭证

  • 4、客户端请求其它功能,携带JWT

  • 5、Zuul将jwt交给授权中心校验,通过后放行

  • 6、用户请求到达微服务

  • 7、微服务将jwt交给鉴权中心,鉴权同时解析用户信息

  • 8、鉴权中心返回用户数据给微服务

  • 9、微服务处理请求,返回响应

缺点:

每次鉴权都需要访问鉴权中心,系统间的网络请求频率过高,效率略差,鉴权中心的压力较大。

1.5.2 结合RSA的鉴权

  • 首先利用RSA生成公钥和私钥。私钥保存在授权中心,公钥保存在Zuul和各个微服务

  • 用户请求登录

  • 授权中心校验,通过后用私钥对JWT进行签名加密

  • 返回jwt给用户

  • 用户携带JWT访问

  • Zuul直接通过公钥解密JWT,进行验证,验证通过则放行

  • 请求到达微服务,微服务直接用公钥解析JWT,获取用户信息,无需访问授权中心

二、授权中心

授权中心的主要职责:

  • 用户鉴权:

    • 接收用户的登录请求,通过用户中心的接口进行校验,通过后生成JWT

    • 使用私钥生成JWT并返回

  • 服务鉴权:微服务间的调用不经过Zuul,会有风险,需要鉴权中心进行认证

    • 原理与用户鉴权类似,但逻辑稍微复杂一些(此处不做实现)

因为生成jwt,解析jwt这样的行为以后在其它微服务中也会用到,因此抽取成工具。把鉴权中心进行聚合,一个工具module,一个提供服务的module。

2.1 创建授权中心

2.1.1 创建父module

将打包方式改为pom:

<?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"><parent><artifactId>leyou</artifactId><groupId>com.leyou.parent</groupId><version>1.0.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.leyou.authentication</groupId><artifactId>leyou-authentication</artifactId><packaging>pom</packaging></project>

2.1.2 通用module

2.1.3 授权服务

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"><parent><artifactId>leyou-authentication</artifactId><groupId>com.leyou.authentication</groupId><version>1.0.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.leyou.authentication</groupId><artifactId>leyou-authentication-service</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.leyou.authentication</groupId><artifactId>leyou-authentication-common</artifactId><version>1.0.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies></project>

启动器

package com.leyou.auth;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;/*** @Author: 98050* @Time: 2018-10-23 20:11* @Feature: 授权服务启动器*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LyAuthApplication {public static void main(String[] args) {SpringApplication.run(LyAuthApplication.class,args);}
}

application.yml

server:port: 8087
spring:application:name: auth-service
eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eurekaregistry-fetch-interval-seconds: 10instance:instance-id: ${spring.application.name}:${server.port}prefer-ip-address: true  #当你获取host时,返回的不是主机名,而是ipip-address: 127.0.0.1lease-expiration-duration-in-seconds: 10 #10秒不发送九过期lease-renewal-interval-in-seconds: 5 #每隔5秒发一次心跳

结构:

在leyou-gateway工程的application.yml中,修改路由:

2.2 JWT工具类

在leyou-authentication-common中导入工具类:

需要在leyou-auth-common中引入JWT依赖:

<?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"><parent><artifactId>leyou-authentication</artifactId><groupId>com.leyou.authentication</groupId><version>1.0.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.leyou.authentication</groupId><artifactId>leyou-authentication-common</artifactId><version>1.0.0-SNAPSHOT</version><dependencies><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency><dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies></project>

2.3 测试工具类

在leyou-authentication-common中编写测试类:

public class JwtTest {private static final String pubKeyPath = "C:\\tmp\\rsa\\rsa.pub";private static final String priKeyPath = "C:\\tmp\\rsa\\rsa.pri";private PublicKey publicKey;private PrivateKey privateKey;@Testpublic void testRsa() throws Exception {RsaUtils.generateKey(pubKeyPath, priKeyPath, "234");}@Beforepublic void testGetRsa() throws Exception {this.publicKey = RsaUtils.getPublicKey(pubKeyPath);this.privateKey = RsaUtils.getPrivateKey(priKeyPath);}@Testpublic void testGenerateToken() throws Exception {// 生成tokenString token = JwtUtils.generateToken(new UserInfo(20L, "jack"), privateKey, 5);System.out.println("token = " + token);}@Testpublic void testParseToken() throws Exception {String token = "eyJhbGciOiJSUzI1NiJ9.eyJpZCI6MjAsInVzZXJuYW1lIjoiamFjayIsImV4cCI6MTUzMzI4MjQ3N30.EPo35Vyg1IwZAtXvAx2TCWuOPnRwPclRNAM4ody5CHk8RF55wdfKKJxjeGh4H3zgruRed9mEOQzWy79iF1nGAnvbkraGlD6iM-9zDW8M1G9if4MX579Mv1x57lFewzEo-zKnPdFJgGlAPtNWDPv4iKvbKOk1-U7NUtRmMsF1Wcg";// 解析tokenUserInfo user = JwtUtils.getInfoFromToken(token, publicKey);System.out.println("id: " + user.getId());System.out.println("userName: " + user.getUsername());}
}

测试生成公钥和私钥,运行代码(注意将testGetRsa方法注释掉):

查看目标目录:

公钥和私钥已经生成了!

测试生成token,把@Before的注释去掉:

测试解析token:

正常解析:

JWT工具类

2.4 编写登录授权接口

接下来,需要在leyou-auth-servcice编写一个接口,对外提供登录授权服务。基本流程如下:

  • 客户端携带用户名和密码请求登录

  • 授权中心调用客户中心接口,根据用户名和密码查询用户信息

  • 如果用户名密码正确,能获取用户,否则为空,则登录失败

  • 如果校验成功,则生成JWT并返回

2.4.1 生成公钥和私钥

在授权中心生成真正的公钥和私钥。所以必须有一个生成公钥和私钥的secret,这个可以配置到application.yml中:

然后编写属性类,加载这些数据:

package com.leyou.auth.properties;import com.leyou.auth.utils.RsaUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;import javax.annotation.PostConstruct;
import java.io.File;
import java.security.PrivateKey;
import java.security.PublicKey;/*** @Author: 98050* @Time: 2018-10-23 22:20* @Feature: jwt配置参数*/
@ConfigurationProperties(prefix = "leyou.jwt")
public class JwtProperties {/*** 密钥*/private String secret;/*** 公钥地址*/private String pubKeyPath;/*** 私钥地址*/private String priKeyPath;/*** token过期时间*/private int expire;/*** 公钥*/private PublicKey publicKey;/*** 私钥*/private PrivateKey privateKey;private static final Logger logger = LoggerFactory.getLogger(JwtProperties.class);public String getSecret() {return secret;}public void setSecret(String secret) {this.secret = secret;}public String getPubKeyPath() {return pubKeyPath;}public void setPubKeyPath(String pubKeyPath) {this.pubKeyPath = pubKeyPath;}public String getPriKeyPath() {return priKeyPath;}public void setPriKeyPath(String priKeyPath) {this.priKeyPath = priKeyPath;}public int getExpire() {return expire;}public void setExpire(int expire) {this.expire = expire;}public PublicKey getPublicKey() {return publicKey;}public void setPublicKey(PublicKey publicKey) {this.publicKey = publicKey;}public PrivateKey getPrivateKey() {return privateKey;}public void setPrivateKey(PrivateKey privateKey) {this.privateKey = privateKey;}/*** @PostConstruct :在构造方法执行之后执行该方法*/@PostConstructpublic void init(){try {File pubKey = new File(pubKeyPath);File priKey = new File(priKeyPath);if (!pubKey.exists() || !priKey.exists()) {// 生成公钥和私钥RsaUtils.generateKey(pubKeyPath, priKeyPath, secret);}// 获取公钥和私钥this.publicKey = RsaUtils.getPublicKey(pubKeyPath);this.privateKey = RsaUtils.getPrivateKey(priKeyPath);} catch (Exception e) {logger.error("初始化公钥和私钥失败!", e);throw new RuntimeException();}}
}

2.4.2 Controller

编写授权接口,接收用户名和密码,校验成功后,写入cookie中。

  • 请求方式:post

  • 请求路径:/accredit

  • 请求参数:username和password

  • 返回结果:无

代码:

注意配置属性类:@EnableConfigurationProperties(JwtProperties.class)

package com.leyou.auth.controller;import com.leyou.auth.properties.JwtProperties;
import com.leyou.auth.service.AuthService;
import com.leyou.utils.CookieUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** @Author: 98050* @Time: 2018-10-23 22:43* @Feature: 登录授权*/
@Controller
@EnableConfigurationProperties(JwtProperties.class)
public class AuthController {@Autowiredprivate AuthService authService;@Autowiredprivate JwtProperties properties;@PostMapping("accredit")public ResponseEntity<Void> authentication(@RequestParam("username") String username,@RequestParam("password") String password,HttpServletRequest request,HttpServletResponse response){//1.登录校验String token = this.authService.authentication(username,password);if (StringUtils.isBlank(token)){return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);}//2.将token写入cookie,并指定httpOnly为true,防止通过js获取和修改CookieUtils.setCookie(request,response,properties.getCookieName(),token,properties.getCookieMaxAge(),true);return ResponseEntity.ok().build();}
}

2.4.3 CookieUtils

作用,将生成好的token放入到cookie中,返回到客户端。

代码:略

2.4.4 UserClient

对用户密码进行校验,所以需要通过FeignClient去访问 user-service微服务:

引入user-service依赖:

<dependency><groupId>com.leyou.user</groupId><artifactId>leyou-user-interface</artifactId><version>1.0.0-SNAPSHOT</version>
</dependency>

编写FeignClient:

package com.leyou.auth.client;import com.leyou.user.api.UserApi;
import org.springframework.cloud.openfeign.FeignClient;/*** @Author: 98050* @Time: 2018-10-23 23:48* @Feature: 用户feignclient*/
@FeignClient(value = "user-service")
public interface UserClient extends UserApi {
}

在leyou-user-interface中添加api接口:

package com.leyou.user.api;import com.leyou.user.pojo.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;/*** @Author: 98050* @Time: 2018-10-23 23:50* @Feature: 用户服务接口*/
public interface UserApi {/*** 用户验证* @param username* @param password* @return*/@GetMapping("query")User queryUser(@RequestParam("username")String username, @RequestParam("password")String password);
}

2.4.5 Service

接口

package com.leyou.auth.service;/*** @Author: 98050* @Time: 2018-10-23 22:46* @Feature:*/
public interface AuthService {/*** 用户授权* @param username* @param password* @return*/String authentication(String username, String password);
}

实现

package com.leyou.auth.service.impl;import com.leyou.auth.client.UserClient;
import com.leyou.auth.entity.UserInfo;
import com.leyou.auth.properties.JwtProperties;
import com.leyou.auth.service.AuthService;
import com.leyou.auth.utils.JwtUtils;
import com.leyou.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** @Author: 98050* @Time: 2018-10-23 22:47* @Feature:*/
@Service
public class AuthServiceImpl implements AuthService {@Autowiredprivate UserClient userClient;@Autowiredprivate JwtProperties properties;/*** 用户授权* @param username* @param password* @return*/@Overridepublic String authentication(String username, String password) {try{//1.调用微服务查询用户信息User user = this.userClient.queryUser(username,password);System.out.println(user);//2.查询结果为空,则直接返回nullif (user == null){return null;}//3.查询结果不为空,则生成tokenString token = JwtUtils.generateToken(new UserInfo(user.getId(), user.getUsername()),properties.getPrivateKey(), properties.getExpire());System.out.println(token);return token;}catch (Exception e){e.printStackTrace();return null;}}
}

2.4.6 项目结构

2.4.7 测试

token已经生成,返回到客户端。

2.5 登录页面

请求路径不对,因为认证接口是:

/api/auth/accredit

修改login.html:

然后登录,可以跳转到首页。

2.6 解决cookie写入问题

查看首页cookie:

2.6.1 问题分析

之前测试时,看到了响应头中,有Set-Cookie属性,为什么在这里却什么都没有?

因为涉及到跨域问题。跨域请求cookie生效的条件:

  • 服务的响应头中需要携带Access-Control-Allow-Credentials并且为true。

  • 响应头中的Access-Control-Allow-Origin一定不能为*,必须是指定的域名

  • 浏览器发起ajax需要指定withCredentials 为true

服务端cors配置:

没有问题。

客户端ajax配置:common.js中

也没有问题。

那说明,问题一定出在响应的set-cookie头中。仔细查看刚才的响应头:

cookie的 domain属性似乎不太对

cookie也是有 的限制,一个网页,只能操作当前域名下的cookie,但是现在看到的地址是0.0.1(为什么是0.0.1,因为前端的地址是www.leyou.com,通过nginx反向代理到127.0.0.1,通过计算得到domain为0.0.1),而页面是www.leyou.com,域名不匹配,cookie设置肯定失败了!

2.6.2 跟踪CookieUtils

再次登录,然后进行Debug

CookieUtils内部有一个获取domain的方法:

它获取domain是通过服务器的host来计算的,然而我们的地址竟然是:127.0.0.1:8087,因此后续的运算,最终得到的domain就变成了:

问题找到了:

请求时的serverName是:api.leyou.com,现在却被变成了127.0.0.1:,因此计算domain是错误的,从而导致cookie设置失败!

2.6.3 解决host地址的变化

那么问题来了:为什么这里的请求serverName变成了:127.0.0.1:8087呢?

这里的server name其实就是请求时的主机名:Host,之所以改变,有两个原因:

  • 使用了nginx反向代理,当监听到api.leyou.com的时候,会自动将请求转发至127.0.0.1:10010,即Zuul。

  • 而后请求到达我们的网关Zuul,Zuul就会根据路径匹配,我们的请求是/api/auth,根据规则被转发到了 127.0.0.1:8087 ,即授权中心。

所以,先更改nginx配置,让它不要修改host:proxy_set_header Host $host;

nginx重启。

然后再去解决Zuul的问题,因为Zuul还会有一次转发,所以要去修改网关的配置(leyou-gateway):

重启项目,再次测试:

最后计算得到domain:

2.6.4 再次测试

还是没有cookie!

2.6.5 Zuul的敏感头过滤

Zuul内部有默认的过滤器,会对请求和响应头信息进行重组,过滤掉敏感的头信息:

会发现,这里会通过一个属性为SensitiveHeaders的属性,来获取敏感头列表,然后添加到IgnoredHeaders中,这些头信息就会被忽略。

而这个SensitiveHeaders的默认值就包含了set-cookie

解决方案有两种:

全局设置:

  • zuul.sensitive-headers=

指定路由设置:

  • zuul.routes.<routeName>.sensitive-headers=

  • zuul.routes.<routeName>.custom-sensitive-headers=true

思路都是把敏感头设置为null

2.6.6 最后的测试

再次重启,登录:

乐优商城(三十)——授权中心相关推荐

  1. 乐优商城(十)用户注册

    文章目录 1. 搭建用户微服务 1.1 用户微服务的结构 1.2 创建 leyou-user 1.3 创建 leyou-user-interface 1.4 创建 leyou-user-service ...

  2. 乐优商城源码/数据库及笔记总结

    文章目录 1 源码 2 笔记 2.1 项目概述 2.2 微服务 3 项目优化 4 项目或学习过程中涉及到的设计模式 5 安全问题 6 高内聚低耦合的体现 7 项目中待优化的地方 1 源码 Github ...

  3. 乐优商城之项目搭建(四)

    文章目录 (一)项目分类 (二)电商行业 (三)专业术语 (四)项目介绍 (五)技术选型 (六)开发环境 (七)搭建后台环境:父工程 (八)搭建后台环境:eureka (九)搭建后台环境:zuul ( ...

  4. leyou商城项目搭建(1)-电商行业及乐优商城介绍

    leyou商城项目搭建(1)-电商行业介绍 1.了解电商行业 1.1.项目分类 1.1.1.传统项目 1.1.2.互联网项目 1.2.电商行业的发展 1.2.1.钱景 1.2.2.数据 1.2.3.技 ...

  5. 【javaWeb微服务架构项目——乐优商城day15】——会调用订单系统接口,实现订单结算功能,实现微信支付功能

    0.学习目标 会调用订单系统接口 实现订单结算功能 实现微信支付功能 源码笔记及资料: 链接:https://pan.baidu.com/s/1_opfL63P1pzH3rzLnbFiNw 提取码:v ...

  6. 乐优商城之分类查询品牌查询(八)

    文章目录 (一)编写分类查询 (二)跨域问题 (三)cors跨域原理 (四)解决跨域问题 (五)品牌查询页面分析 (六)品牌查询后台代码 (七)分页查询排序的原理 (八)axios (一)编写分类查询 ...

  7. 乐优商城(05)--商品管理

    乐优商城(05)–商品管理 一.导入图片资源 现在商品表中虽然有数据,但是所有的图片信息都是无法访问的,因此需要把图片导入到服务器中: 将images.zip文件上传至/leyou/static目录: ...

  8. 乐优商城(填坑)——后台登录

    后台管理模块增加登录验证,与门户网站一样都是采用无状态登录. 一.新增全局函数 在main.js中新增用户验证: 二.修改路由 先显示登录页面 效果: 三.解决cookie写入问题 在http.js中 ...

  9. 乐优商城(10)--数据同步

    乐优商城(10)–数据同步 一.RabbitMQ 1.1.问题分析 目前已经完成了商品详情和搜索系统的开发.思考一下,是否存在问题? 商品的原始数据保存在数据库中,增删改查都在数据库中完成. 搜索服务 ...

  10. 【javaWeb微服务架构项目——乐优商城day03】——(搭建后台管理前端,Vuetify框架,使用域名访问本地项目,实现商品分类查询,cors解决跨域,品牌的查询)

    乐优商城day03 0.学习目标 1.搭建后台管理前端 1.1.导入已有资源 1.2.安装依赖 1.3.运行一下看看 1.4.目录结构 1.5.调用关系 2.Vuetify框架 2.1.为什么要学习U ...

最新文章

  1. #1045 - Access denied for user 'root'@'localhost' (using password: NO)
  2. 程序员保值的5个秘密
  3. 2019\Province_C_C++_B\试题G-完全二叉树的权值
  4. idea2020shezhi代码检查级别_ICT技术:阿里巴巴代码缺陷检测探索与实践
  5. Java多线程之静态代理
  6. 内存泄漏——内存溢出区别
  7. 打开c语言运行不了_C语言——菜鸟和大神的分水岭:内存、线程、进程
  8. echarts js 删除框选数据_ECharts进行区域选择
  9. 把人物用 Unity 进行 2D 传送,拢共分四步 | 原力计划
  10. 安防蓝海带来亿万商机 汉王人脸通掀起产业风暴
  11. git lfs mac 安装_Git LFS
  12. Pillow为图片添加水印
  13. Linux的触屏手势软件安装,linux触摸板手势
  14. 关于Windows下模拟Shift+END(功能键)无效问题
  15. 前端教程:用 Canvas 编织璀璨星空图
  16. KindEditor在线文本编辑器
  17. 【面试概率题连载2】轻率的陪审团
  18. 如何快速达到团队的销售目标
  19. 美国盗版党(Pirate Party)
  20. 如何使用VS2015编译运行DX11版本龙书配套源码

热门文章

  1. 【分治法】逆序对的数量(结合归并排序,含详细思想、解法、代码及注释)
  2. C语言中字符型(char)的简单使用
  3. FFmpeg实现音频解码并播放
  4. lumia1520 越狱_尝试诺基亚Lumia 1020-内置电话的相机
  5. PHP还款,ThinkPHP内核借贷管理系统安装版
  6. Outlook 2007无法连接Exchange 2007
  7. 【企业邮箱申请】网易企业邮箱陌生人来信安全提醒功能
  8. Shader学习之Cg语言三(Cg表达式与控制语句)
  9. 笔记本下键android,安卓联姻Windows?华硕双系统变形本体验
  10. 运放脉冲宽度放大_下一代Ka波段雷达系统应用脉冲行波管放大器(twta),工作频率为34至36GHz,峰值功率为1000瓦,占空比为10%。...