第三章 app端用户认证

目标

  • 能够完成网关统一鉴权的功能

  • 能够完成认证用户列表查询

  • 能够熟悉app端用户认证审核流程

  • 能够完成app用户审核代码开发

1 网关校验jwt

1.1 微服务网关概述

不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

  • 客户端会多次请求不同的微服务,增加了客户端的复杂性
  • 存在跨域请求,在一定场景下处理相对复杂
  • 认证复杂,每个服务都需要独立认证
  • 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施
  • 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难

以上这些问题可以借助网关解决。

网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 网关来做,这样既提高业务灵活性又不缺安全性,典型的架构图如图所示:

第三章 用户认证 - 图1

优点如下:

  • 安全 ,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。
  • 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
  • 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
  • 减少了客户端与各个微服务之间的交互次数
  • 易于统一授权。

总结:微服务网关就是一个系统,通过暴露该微服务网关系统,方便我们进行相关的鉴权,安全控制,日志统一处理,易于监控的相关功能。

实现微服务网关的技术有很多,

  • nginx Nginx (engine x) 是一个高性能的HTTP反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务
  • zuul ,Zuul 是 Netflix 出品的一个基于 JVM 路由和服务端的负载均衡器。
  • spring-cloud-gateway, 是spring 出品的 基于spring 的网关项目,集成断路器,路径重写,性能比Zuul好。

我们使用gateway这个网关技术,无缝衔接到基于spring cloud的微服务开发中来。

gateway官网:

https://spring.io/projects/spring-cloud-gateway

1.2 搭建gatway网关微服务

(1)创建heima-leadnews-admin-gateway微服务

pom文件

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.alibaba.cloud</groupId>
  8. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>io.jsonwebtoken</groupId>
  12. <artifactId>jjwt</artifactId>
  13. </dependency>
  14. </dependencies>

引导类:

  1. package com.heima.admin.gateway;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. @SpringBootApplication
  6. @EnableDiscoveryClient //开启注册中心
  7. public class GatewayApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(GatewayApplication.class,args);
  10. }
  11. }

application.yml

  1. server:
  2. port: 6001
  3. spring:
  4. application:
  5. name: leadnews-admin-gateway
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 192.168.200.130:8848
  10. gateway:
  11. globalcors:
  12. cors-configurations:
  13. '[/**]': # 匹配所有请求
  14. allowedOrigins: "*" #跨域处理 允许所有的域
  15. allowedMethods: # 支持的方法
  16. - GET
  17. - POST
  18. - PUT
  19. - DELETE
  20. routes:
  21. # 平台管理
  22. - id: admin
  23. uri: lb://leadnews-admin
  24. predicates:
  25. - Path=/admin/**
  26. filters:
  27. - StripPrefix= 1

1.3 全局过滤器实现jwt校验

第三章 用户认证 - 图2

思路分析:

  1. 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录
  2. 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户
  3. 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN
  4. 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误

在网关微服务中新建全局过滤器:

第一步,准备工具类

把heima-leadnews-utils模块中的AppJwtUtil类拷贝到网关模块下,如下图:

第三章 用户认证 - 图3

第二步,编写全局过滤器

  1. package com.heima.admin.gateway.filter;
  2. import com.heima.admin.gateway.utils.AppJwtUtil;
  3. import io.jsonwebtoken.Claims;
  4. import lombok.extern.log4j.Log4j2;
  5. import org.apache.commons.lang3.StringUtils;
  6. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  7. import org.springframework.cloud.gateway.filter.GlobalFilter;
  8. import org.springframework.core.Ordered;
  9. import org.springframework.http.HttpHeaders;
  10. import org.springframework.http.HttpStatus;
  11. import org.springframework.http.server.reactive.ServerHttpRequest;
  12. import org.springframework.http.server.reactive.ServerHttpResponse;
  13. import org.springframework.stereotype.Component;
  14. import org.springframework.web.server.ServerWebExchange;
  15. import reactor.core.publisher.Mono;
  16. @Component
  17. @Log4j2
  18. public class AuthorizeFilter implements GlobalFilter, Ordered {
  19. @Override
  20. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  21. //1.获取请求对象和响应对象
  22. ServerHttpRequest request = exchange.getRequest();
  23. ServerHttpResponse response = exchange.getResponse();
  24. //2.判断当前的请求是否为登录,如果是,直接放行
  25. if(request.getURI().getPath().contains("/login/in")){
  26. //放行
  27. return chain.filter(exchange);
  28. }
  29. //3.获取当前用户的请求头jwt信息
  30. HttpHeaders headers = request.getHeaders();
  31. String jwtToken = headers.getFirst("token");
  32. //4.判断当前令牌是否存在
  33. if(StringUtils.isEmpty(jwtToken)){
  34. //如果不存在,向客户端返回错误提示信息
  35. response.setStatusCode(HttpStatus.UNAUTHORIZED);
  36. return response.setComplete();
  37. }
  38. try {
  39. //5.如果令牌存在,解析jwt令牌,判断该令牌是否合法,如果不合法,则向客户端返回错误信息
  40. Claims claims = AppJwtUtil.getClaimsBody(jwtToken);
  41. int result = AppJwtUtil.verifyToken(claims);
  42. if(result == 0 || result == -1){
  43. //5.1 合法,则向header中重新设置userId
  44. Integer id = (Integer) claims.get("id");
  45. log.info("find userid:{} from uri:{}",id,request.getURI());
  46. //重新设置token到header中
  47. ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
  48. httpHeaders.add("userId", id + "");
  49. }).build();
  50. exchange.mutate().request(serverHttpRequest).build();
  51. }
  52. }catch (Exception e){
  53. e.printStackTrace();
  54. //想客户端返回错误提示信息
  55. response.setStatusCode(HttpStatus.UNAUTHORIZED);
  56. return response.setComplete();
  57. }
  58. //6.放行
  59. return chain.filter(exchange);
  60. }
  61. /**
  62. * 优先级设置
  63. * 值越小,优先级越高
  64. * @return
  65. */
  66. @Override
  67. public int getOrder() {
  68. return 0;
  69. }
  70. }

测试:

启动admin服务,继续访问其他微服务,会提示需要认证才能访问,这个时候需要在heads中设置设置token才能正常访问。

2 app端用户认证列表查询

2.1 需求分析

第三章 用户认证 - 图4

当用户在app前端进行了认证请求会自动往ap_user_realname表中加入数据,目前所查询的就是用户认证列表

默认查询待审核的信息,也可以根据状态进行过滤

ap_user_realname

第三章 用户认证 - 图5

对应的实体类:

  1. package com.heima.model.user.pojos;
  2. import com.baomidou.mybatisplus.annotation.IdType;
  3. import com.baomidou.mybatisplus.annotation.TableField;
  4. import com.baomidou.mybatisplus.annotation.TableId;
  5. import com.baomidou.mybatisplus.annotation.TableName;
  6. import lombok.Data;
  7. import java.io.Serializable;
  8. import java.util.Date;
  9. /**
  10. * <p>
  11. * APP实名认证信息表
  12. * </p>
  13. *
  14. * @author itheima
  15. */
  16. @Data
  17. @TableName("ap_user_realname")
  18. public class ApUserRealname implements Serializable {
  19. private static final long serialVersionUID = 1L;
  20. /**
  21. * 主键
  22. */
  23. @TableId(value = "id", type = IdType.AUTO)
  24. private Integer id;
  25. /**
  26. * 账号ID
  27. */
  28. @TableField("user_id")
  29. private Integer userId;
  30. /**
  31. * 用户名称
  32. */
  33. @TableField("name")
  34. private String name;
  35. /**
  36. * 资源名称
  37. */
  38. @TableField("idno")
  39. private String idno;
  40. /**
  41. * 正面照片
  42. */
  43. @TableField("font_image")
  44. private String fontImage;
  45. /**
  46. * 背面照片
  47. */
  48. @TableField("back_image")
  49. private String backImage;
  50. /**
  51. * 手持照片
  52. */
  53. @TableField("hold_image")
  54. private String holdImage;
  55. /**
  56. * 活体照片
  57. */
  58. @TableField("live_image")
  59. private String liveImage;
  60. /**
  61. * 状态
  62. 0 创建中
  63. 1 待审核
  64. 2 审核失败
  65. 9 审核通过
  66. */
  67. @TableField("status")
  68. private Short status;
  69. /**
  70. * 拒绝原因
  71. */
  72. @TableField("reason")
  73. private String reason;
  74. /**
  75. * 创建时间
  76. */
  77. @TableField("created_time")
  78. private Date createdTime;
  79. /**
  80. * 提交时间
  81. */
  82. @TableField("submited_time")
  83. private Date submitedTime;
  84. /**
  85. * 更新时间
  86. */
  87. @TableField("updated_time")
  88. private Date updatedTime;
  89. }

2.2 新建user微服务

(1)新建模块:heima-leadnews-user

  • 定义包名
  • 新建引导类 参考其他微服务创建
  • pom文件引入,参考其他微服务

第三章 用户认证 - 图6

(3)在resources下新建application.yml

  1. server:
  2. port: 9002
  3. spring:
  4. application:
  5. name: leadnews-user
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 192.168.200.130:8848
  10. datasource:
  11. driver-class-name: com.mysql.jdbc.Driver
  12. url: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
  13. username: root
  14. password: root
  15. # 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
  16. mybatis-plus:
  17. mapper-locations: classpath*:mapper/*.xml
  18. # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  19. type-aliases-package: com.heima.model.user.pojos

2.3 接口定义

在heima-leadnews-apis模块中新增接口:com.heima.api.user.ApUserRealnameControllerApi

  1. package com.heima.api.user;
  2. import com.heima.model.common.dtos.PageResponseResult;
  3. import com.heima.model.user.dtos.AuthDto;
  4. public interface ApUserRealnameControllerApi {
  5. /**
  6. *按照状态查询用户认证列表
  7. * @param dto
  8. * @return
  9. */
  10. public PageResponseResult loadListByStatus(AuthDto dto);
  11. }

AuthDto

  1. package com.heima.model.user.dtos;
  2. import com.heima.model.common.dtos.PageRequestDto;
  3. import lombok.Data;
  4. @Data
  5. public class AuthDto extends PageRequestDto {
  6. private Integer id;
  7. //驳回的信息
  8. private String msg;
  9. //状态
  10. private Short status;
  11. }

2.4 mapper

在user微服务下新建mapper接口:com.heima.user.mapper.ApUserRealnameMapper

  1. package com.heima.user.mapper;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import com.heima.model.user.pojos.ApUserRealname;
  4. import org.apache.ibatis.annotations.Mapper;
  5. @Mapper
  6. public interface ApUserRealnameMapper extends BaseMapper<ApUserRealname> {
  7. }

2.5 业务层

新建业务层接口:com.heima.user.service.ApUserRealnameService

  1. package com.heima.user.service;
  2. import com.baomidou.mybatisplus.extension.service.IService;
  3. import com.heima.model.common.dtos.PageResponseResult;
  4. import com.heima.model.user.dtos.AuthDto;
  5. import com.heima.model.user.pojos.ApUserRealname;
  6. public interface ApUserRealnameService extends IService<ApUserRealname> {
  7. /**
  8. * 根据状态查询需要认证相关的用户信息
  9. * @param dto
  10. * @return
  11. */
  12. PageResponseResult loadListByStatus(AuthDto dto);
  13. }

实现类:

  1. package com.heima.user.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  3. import com.baomidou.mybatisplus.core.metadata.IPage;
  4. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  5. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  6. import com.heima.model.common.dtos.PageResponseResult;
  7. import com.heima.model.common.dtos.ResponseResult;
  8. import com.heima.model.common.enums.AppHttpCodeEnum;
  9. import com.heima.model.user.dtos.AuthDto;
  10. import com.heima.model.user.pojos.ApUserRealname;
  11. import com.heima.user.mapper.ApUserRealnameMapper;
  12. import com.heima.user.service.ApUserRealnameService;
  13. import org.springframework.stereotype.Service;
  14. @Service
  15. public class ApUserRealnameServiceImpl extends ServiceImpl<ApUserRealnameMapper, ApUserRealname> implements ApUserRealnameService {
  16. @Override
  17. public PageResponseResult loadListByStatus(AuthDto dto) {
  18. //参数为空
  19. if (dto == null) {
  20. return (PageResponseResult) ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
  21. }
  22. //检查参数
  23. dto.checkParam();
  24. QueryWrapper<ApUserRealname> queryWrapper = new QueryWrapper<ApUserRealname>();
  25. if(dto.getStatus()!=null){
  26. queryWrapper.lambda().eq(ApUserRealname::getStatus,dto.getStatus());
  27. }
  28. IPage pageParam = new Page(dto.getPage(),dto.getSize());
  29. IPage page = page(pageParam, queryWrapper);
  30. PageResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(),(int)page.getTotal());
  31. responseResult.setCode(0);
  32. responseResult.setData(page.getRecords());
  33. return responseResult;
  34. }
  35. }

2.6 控制层

  1. package com.heima.user.controller.v1;
  2. import com.heima.api.user.ApUserRealnameControllerApi;
  3. import com.heima.model.common.dtos.PageResponseResult;
  4. import com.heima.model.user.dtos.AuthDto;
  5. import com.heima.user.service.ApUserRealnameService;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.web.bind.annotation.PostMapping;
  8. import org.springframework.web.bind.annotation.RequestBody;
  9. import org.springframework.web.bind.annotation.RequestMapping;
  10. import org.springframework.web.bind.annotation.RestController;
  11. @RestController
  12. @RequestMapping("/api/v1/auth")
  13. public class ApUserRealnameController implements ApUserRealnameControllerApi {
  14. @Autowired
  15. private ApUserRealnameService userRealnameService;
  16. @PostMapping("/list")
  17. @Override
  18. public PageResponseResult loadListByStatus(@RequestBody AuthDto dto){
  19. return userRealnameService.loadListByStatus(dto);
  20. }
  21. }

2.7 测试

打开前端工程整合测试

3 app端用户认证后审核

3.1 需求分析

第三章 用户认证 - 图7

流程说明

第三章 用户认证 - 图8

  • 在app端的个人中心用户可以实名认证,需要材料为:姓名、身份证号、身份证正面照、身份证反面照、手持照片、活体照片(通过微笑、眨眼、张嘴、摇头、点头等组合动作,确保操作的为真实活体人脸。),当用户提交审核后就到了后端让运营管理人员进行审核
  • 平台运营端查看用户认证信息,进行审核,其中审核包括了用户身份审核,需要对接公安系统校验身份证信息
  • 用户通过审核后需要开通自媒体账号(该账号的用户名和密码与app一致)
  • 用户通过审核后需要在article中在作者表中新建一个作者信息

3.2 自媒体用户保存

3.2.1 wemedia微服务搭建

(1)新建heima-leadnews-wemedia模块,引导类和pom配置参考其他微服务

第三章 用户认证 - 图9

(2)resources下新建application.yml

  1. server:
  2. port: 9004
  3. spring:
  4. application:
  5. name: leadnews-wemedia
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 192.168.200.130:8848
  10. datasource:
  11. driver-class-name: com.mysql.jdbc.Driver
  12. url: jdbc:mysql://localhost:3306/leadnews_wemedia?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
  13. username: root
  14. password: root
  15. # 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
  16. mybatis-plus:
  17. mapper-locations: classpath*:mapper/*.xml
  18. # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  19. type-aliases-package: com.heima.model.media.pojos

3.2.2 自媒体用户保存和按照用户名查询

wm_user 自媒体用户表

第三章 用户认证 - 图10

实体类:

  1. package com.heima.model.media.pojos;
  2. import com.baomidou.mybatisplus.annotation.IdType;
  3. import com.baomidou.mybatisplus.annotation.TableField;
  4. import com.baomidou.mybatisplus.annotation.TableId;
  5. import com.baomidou.mybatisplus.annotation.TableName;
  6. import lombok.Data;
  7. import java.io.Serializable;
  8. import java.util.Date;
  9. /**
  10. * <p>
  11. * 自媒体用户信息表
  12. * </p>
  13. *
  14. * @author itheima
  15. */
  16. @Data
  17. @TableName("wm_user")
  18. public class WmUser implements Serializable {
  19. private static final long serialVersionUID = 1L;
  20. /**
  21. * 主键
  22. */
  23. @TableId(value = "id", type = IdType.AUTO)
  24. private Integer id;
  25. @TableField("ap_user_id")
  26. private Integer apUserId;
  27. @TableField("ap_author_id")
  28. private Integer apAuthorId;
  29. /**
  30. * 登录用户名
  31. */
  32. @TableField("name")
  33. private String name;
  34. /**
  35. * 登录密码
  36. */
  37. @TableField("password")
  38. private String password;
  39. /**
  40. * 盐
  41. */
  42. @TableField("salt")
  43. private String salt;
  44. /**
  45. * 昵称
  46. */
  47. @TableField("nickname")
  48. private String nickname;
  49. /**
  50. * 头像
  51. */
  52. @TableField("image")
  53. private String image;
  54. /**
  55. * 归属地
  56. */
  57. @TableField("location")
  58. private String location;
  59. /**
  60. * 手机号
  61. */
  62. @TableField("phone")
  63. private String phone;
  64. /**
  65. * 状态
  66. 0 暂时不可用
  67. 1 永久不可用
  68. 9 正常可用
  69. */
  70. @TableField("status")
  71. private Integer status;
  72. /**
  73. * 邮箱
  74. */
  75. @TableField("email")
  76. private String email;
  77. /**
  78. * 账号类型
  79. 0 个人
  80. 1 企业
  81. 2 子账号
  82. */
  83. @TableField("type")
  84. private Integer type;
  85. /**
  86. * 运营评分
  87. */
  88. @TableField("score")
  89. private Integer score;
  90. /**
  91. * 最后一次登录时间
  92. */
  93. @TableField("login_time")
  94. private Date loginTime;
  95. /**
  96. * 创建时间
  97. */
  98. @TableField("created_time")
  99. private Date createdTime;
  100. }

(1)接口定义

在heima-leadnews-apis中新建接口:com.heima.api.wemedia.WmUserControllerApi

  1. package com.heima.api.wemedia;
  2. import com.heima.model.common.dtos.ResponseResult;
  3. import com.heima.model.media.pojos.WmUser;
  4. public interface WmUserControllerApi {
  5. /**
  6. * 保存自媒体用户
  7. * @param wmUser
  8. * @return
  9. */
  10. public ResponseResult save(WmUser wmUser);
  11. /**
  12. * 按照名称查询用户
  13. * @param name
  14. * @return
  15. */
  16. public WmUser findByName(String name);
  17. }

(2)mapper定义

新建接口com.heima.wemedia.mapper.WmUserMapper

  1. package com.heima.wemedia.mapper;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import com.heima.model.media.pojos.WmUser;
  4. import org.apache.ibatis.annotations.Mapper;
  5. @Mapper
  6. public interface WmUserMapper extends BaseMapper<WmUser> {
  7. }

(3)业务层

新建接口:com.heima.wemedia.service.WmUserService

  1. package com.heima.wemedia.service;
  2. import com.baomidou.mybatisplus.extension.service.IService;
  3. import com.heima.model.media.pojos.WmUser;
  4. public interface WmUserService extends IService<WmUser> {
  5. }

实现类:

  1. package com.heima.wemedia.service.impl;
  2. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  3. import com.heima.model.media.pojos.WmUser;
  4. import com.heima.wemedia.mapper.WmUserMapper;
  5. import com.heima.wemedia.service.WmUserService;
  6. import org.springframework.stereotype.Service;
  7. @Service
  8. public class WmUserServiceImpl extends ServiceImpl<WmUserMapper, WmUser> implements WmUserService {
  9. }

(4)控制层

  1. @RestController
  2. @RequestMapping("/api/v1/user")
  3. public class WmUserController implements WmUserControllerApi {
  4. @Autowired
  5. private WmUserService userService;
  6. @PostMapping("/save")
  7. @Override
  8. public ResponseResult save(@RequestBody WmUser wmUser){
  9. userService.save(wmUser);
  10. return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
  11. }
  12. @GetMapping("/findByName/{name}")
  13. @Override
  14. public WmUser findByName(@PathVariable("name") String name){
  15. List<WmUser> list = userService.list(Wrappers.<WmUser>lambdaQuery().eq(WmUser::getName, name));
  16. if(list!=null && !list.isEmpty()){
  17. return list.get(0);
  18. }
  19. return null;
  20. }
  21. }

3.3 创建作者

3.3.1 article微服务创建

(1)新建模块heima-leadnews-article,其中引导类和pom文件依赖参考其他微服务

第三章 用户认证 - 图11

(2)resources下新建application.yml

  1. server:
  2. port: 9003
  3. spring:
  4. application:
  5. name: leadnews-article
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 192.168.200.130:8848
  10. datasource:
  11. driver-class-name: com.mysql.jdbc.Driver
  12. url: jdbc:mysql://localhost:3306/leadnews_article?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
  13. username: root
  14. password: root
  15. # 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
  16. mybatis-plus:
  17. mapper-locations: classpath*:mapper/*.xml
  18. # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  19. type-aliases-package: com.heima.model.article.pojos

3.3.2 查询作者和保存作者

ap_author 作者信息表

第三章 用户认证 - 图12

对应实体类:

  1. package com.heima.model.article.pojos;
  2. import com.baomidou.mybatisplus.annotation.IdType;
  3. import com.baomidou.mybatisplus.annotation.TableField;
  4. import com.baomidou.mybatisplus.annotation.TableId;
  5. import com.baomidou.mybatisplus.annotation.TableName;
  6. import lombok.Data;
  7. import java.io.Serializable;
  8. import java.util.Date;
  9. /**
  10. * <p>
  11. * APP文章作者信息表
  12. * </p>
  13. *
  14. * @author itheima
  15. */
  16. @Data
  17. @TableName("ap_author")
  18. public class ApAuthor implements Serializable {
  19. private static final long serialVersionUID = 1L;
  20. /**
  21. * 主键
  22. */
  23. @TableId(value = "id", type = IdType.AUTO)
  24. private Integer id;
  25. /**
  26. * 作者名称
  27. */
  28. @TableField("name")
  29. private String name;
  30. /**
  31. * 0 爬取数据
  32. 1 签约合作商
  33. 2 平台自媒体人
  34. */
  35. @TableField("type")
  36. private Integer type;
  37. /**
  38. * 社交账号ID
  39. */
  40. @TableField("user_id")
  41. private Integer userId;
  42. /**
  43. * 创建时间
  44. */
  45. @TableField("created_time")
  46. private Date createdTime;
  47. /**
  48. * 自媒体账号
  49. */
  50. @TableField("wm_user_id")
  51. private Integer wmUserId;
  52. }

(1)接口定义:com.heima.api.article.AuthorControllerApi

  1. package com.heima.api.article;
  2. import com.heima.model.article.pojos.ApAuthor;
  3. import com.heima.model.common.dtos.ResponseResult;
  4. import org.springframework.web.bind.annotation.PathVariable;
  5. import org.springframework.web.bind.annotation.RequestBody;
  6. public interface AuthorControllerApi {
  7. /**
  8. *根据用户id查询作者信息
  9. * @param id
  10. * @return
  11. */
  12. public ApAuthor findByUserId(@PathVariable("id") Integer id);
  13. /**
  14. * 保存作者
  15. * @param apAuthor
  16. * @return
  17. */
  18. public ResponseResult save(@RequestBody ApAuthor apAuthor);
  19. }

(2)mapper接口

新建mapper接口:com.heima.article.mapper.AuthorMapper

  1. package com.heima.article.mapper;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import com.heima.model.article.pojos.ApAuthor;
  4. import org.apache.ibatis.annotations.Mapper;
  5. @Mapper
  6. public interface AuthorMapper extends BaseMapper<ApAuthor> {
  7. }

(3)业务层

新建接口:com.heima.article.service.AuthorService

  1. package com.heima.article.service;
  2. import com.baomidou.mybatisplus.extension.service.IService;
  3. import com.heima.model.article.pojos.ApAuthor;
  4. public interface AuthorService extends IService<ApAuthor> {
  5. }

实现类:

  1. package com.heima.article.service.impl;
  2. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  3. import com.heima.article.mapper.AuthorMapper;
  4. import com.heima.article.service.AuthorService;
  5. import com.heima.model.article.pojos.ApAuthor;
  6. import org.springframework.stereotype.Service;
  7. @Service
  8. public class AuthorServiceImpl extends ServiceImpl<AuthorMapper, ApAuthor> implements AuthorService {
  9. }

(4)控制层

新建控制器:com.heima.article.controller.AuthorController

  1. package com.heima.article.controller.v1;
  2. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  3. import com.heima.api.article.AuthorControllerApi;
  4. import com.heima.article.service.AuthorService;
  5. import com.heima.model.article.pojos.ApAuthor;
  6. import com.heima.model.common.dtos.ResponseResult;
  7. import com.heima.model.common.enums.AppHttpCodeEnum;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.web.bind.annotation.*;
  10. import java.util.List;
  11. @RestController
  12. @RequestMapping("/api/v1/author")
  13. public class AuthorController implements AuthorControllerApi {
  14. @Autowired
  15. private AuthorService authorService;
  16. @GetMapping("/findByUserId/{id}")
  17. @Override
  18. public ApAuthor findByUserId(@PathVariable("id") Integer id){
  19. List<ApAuthor> list = authorService.list(Wrappers.<ApAuthor>lambdaQuery().eq(ApAuthor::getUserId, id));
  20. if(list!=null &&!list.isEmpty()){
  21. return list.get(0);
  22. }
  23. return null;
  24. }
  25. @PostMapping("/save")
  26. @Override
  27. public ResponseResult save(@RequestBody ApAuthor apAuthor){
  28. apAuthor.setCreatedTime(new Date());
  29. authorService.save(apAuthor);
  30. return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
  31. }
  32. }

3.4 用户审核接口定义

修改com.heima.api.user.ApUserRealnameControllerApi新增方法

  1. /**
  2. * 审核通过
  3. * @param dto
  4. * @return
  5. */
  6. public ResponseResult authPass(AuthDto dto) ;
  7. /**
  8. * 审核失败
  9. * @param dto
  10. * @return
  11. */
  12. public ResponseResult authFail(AuthDto dto);

修改AuthDto

3.5 用户审核mapper接口定义

在新建自媒体账户时需要把apuser信息赋值给自媒体用户

app端用户信息表

第三章 用户认证 - 图13

在heima-leadnews-model中新增实体类

  1. package com.heima.model.user.pojos;
  2. import com.baomidou.mybatisplus.annotation.IdType;
  3. import com.baomidou.mybatisplus.annotation.TableId;
  4. import java.io.Serializable;
  5. import java.util.Date;
  6. import lombok.Data;
  7. import com.baomidou.mybatisplus.annotation.TableField;
  8. import com.baomidou.mybatisplus.annotation.TableName;
  9. /**
  10. * <p>
  11. * APP用户信息表
  12. * </p>
  13. *
  14. * @author itheima
  15. */
  16. @Data
  17. @TableName("ap_user")
  18. public class ApUser implements Serializable {
  19. private static final long serialVersionUID = 1L;
  20. /**
  21. * 主键
  22. */
  23. @TableId(value = "id", type = IdType.AUTO)
  24. private Integer id;
  25. /**
  26. * 密码、通信等加密盐
  27. */
  28. @TableField("salt")
  29. private String salt;
  30. /**
  31. * 用户名
  32. */
  33. @TableField("name")
  34. private String name;
  35. /**
  36. * 密码,md5加密
  37. */
  38. @TableField("password")
  39. private String password;
  40. /**
  41. * 手机号
  42. */
  43. @TableField("phone")
  44. private String phone;
  45. /**
  46. * 头像
  47. */
  48. @TableField("image")
  49. private String image;
  50. /**
  51. * 0 男
  52. 1 女
  53. 2 未知
  54. */
  55. @TableField("sex")
  56. private Boolean sex;
  57. /**
  58. * 0 未
  59. 1 是
  60. */
  61. @TableField("is_certification")
  62. private Boolean certification;
  63. /**
  64. * 是否身份认证
  65. */
  66. @TableField("is_identity_authentication")
  67. private Boolean identityAuthentication;
  68. /**
  69. * 0正常
  70. 1锁定
  71. */
  72. @TableField("status")
  73. private Boolean status;
  74. /**
  75. * 0 普通用户
  76. 1 自媒体人
  77. 2 大V
  78. */
  79. @TableField("flag")
  80. private Boolean flag;
  81. /**
  82. * 注册时间
  83. */
  84. @TableField("created_time")
  85. private Date createdTime;
  86. }

在heima-leadnews-user模块中新增mapper接口

  1. package com.heima.user.mapper;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import com.heima.model.user.pojos.ApUser;
  4. import org.apache.ibatis.annotations.Mapper;
  5. @Mapper
  6. public interface ApUserMapper extends BaseMapper<ApUser> {
  7. }

3.6 feign远程接口定义

3.6.1 user微服务开启远程调用

修改pom文件,加入依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>

修改引导类,添加注解@EnableFeignClients开启远程调用

  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. @EnableFeignClients
  4. @MapperScan("com.heima.user.mapper")
  5. public class UserApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(UserApplication.class,args);
  8. }
  9. /**
  10. * mybatis-plus分页插件
  11. */
  12. @Bean
  13. public PaginationInterceptor paginationInterceptor() {
  14. return new PaginationInterceptor();
  15. }
  16. }

3.6.2 自媒体远程接口

新建接口com.heima.user.feign.ApAuthorFeign

  1. @FeignClient("leadnews-article")
  2. public interface ArticleFeign {
  3. @GetMapping("/api/v1/author/findByUserId/{id}")
  4. public ApAuthor findByUserId(@PathVariable("id") Integer id);
  5. @PostMapping("/api/v1/author/save")
  6. public ResponseResult save(@RequestBody ApAuthor apAuthor);
  7. }

3.6.3 作者远程调用接口

新建接口:com.heima.user.feign.WmUserFeign

  1. @FeignClient("leadnews-wemedia")
  2. public interface WemediaFeign {
  3. @PostMapping("/api/v1/user/save")
  4. public ResponseResult save(@RequestBody WmUser wmUser);
  5. @GetMapping("/api/v1/user/findByName/{name}")
  6. public WmUser findByName(@PathVariable("name") String name);
  7. }

3.7 用户审核业务层

新建常量类:com.heima.common.constants.user.UserConstants

  1. public class AdminConstans {
  2. public static final Short PASS_AUTH = 9;
  3. public static final Short FAIL_AUTH = 2;
  4. }

修改:ApUserRealnameService 新增修改状态方法

  1. /**
  2. * 根据状态进行审核
  3. * @param dto
  4. * @param status
  5. * @return
  6. */
  7. ResponseResult updateStatusById(AuthDto dto, Short status);

实现类:

  1. @Autowired
  2. private ArticleFeign articleFeign;
  3. @Autowired
  4. private WemediaFeign wemediaFeign;
  5. @Autowired
  6. private ApUserMapper apUserMapper;
  7. @Override
  8. @Transactional
  9. public ResponseResult updateStatusById(AuthDto dto, Short status) {
  10. //1.检查参数
  11. if (dto == null || dto.getId()==null) {
  12. return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
  13. }
  14. if (statusCheck(status)) {
  15. return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
  16. }
  17. //2.修改状态
  18. ApUserRealname apUserRealname = new ApUserRealname();
  19. apUserRealname.setId(dto.getId());
  20. apUserRealname.setStatus(status);
  21. if (dto.getMsg() != null){
  22. apUserRealname.setReason(dto.getMsg());
  23. }
  24. updateById(apUserRealname);
  25. //3 认证通过添加自媒体账号和作者账号
  26. if (status.equals(AdminConstans.PASS_AUTH)) {
  27. ResponseResult createResult = createWmUserAndAuthor(dto);
  28. if (createResult != null) {
  29. return createResult;
  30. }
  31. //TODO 发送通知消息
  32. }
  33. return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
  34. }
  35. /**
  36. * 创建自媒体账号, 以及作者账号
  37. * @param dto
  38. * @return
  39. */
  40. private ResponseResult createWmUserAndAuthor(AuthDto dto) {
  41. //添加自媒体账号, 查询ap_user信息封装到wmuser中
  42. ApUserRealname aur = getById(dto.getId());
  43. ApUser apUser = apUserMapper.selectById(aur.getUserId());
  44. if (apUser == null) {
  45. return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
  46. }
  47. // 检测自媒体用户是否存在
  48. WmUser wmUser = wemediaFeign.findByName(apUser.getName());
  49. if (wmUser == null || wmUser.getId()==null) {
  50. wmUser = new WmUser();
  51. //设置ApUserId
  52. wmUser.setApUserId(apUser.getId());
  53. wmUser.setCreatedTime(new Date());
  54. wmUser.setSalt(apUser.getSalt());
  55. wmUser.setName(apUser.getName());
  56. wmUser.setPassword(apUser.getPassword());
  57. wmUser.setStatus(9);
  58. wmUser.setPhone(apUser.getPhone());
  59. wemediaFeign.save(wmUser);
  60. }
  61. //创建作者账号
  62. createAuthor(wmUser);
  63. //修改ap_user标记
  64. apUser.setFlag(1);
  65. apUserMapper.updateById(apUser);
  66. return null;
  67. }
  68. /**
  69. * 创建自媒体账号
  70. * @param wmUser
  71. * @return
  72. */
  73. private void createAuthor(WmUser wmUser) {
  74. Integer apUserId = wmUser.getApUserId();
  75. ApAuthor apAuthor = articleFeign.findByUserId(apUserId);
  76. if (apAuthor == null) {
  77. apAuthor = new ApAuthor();
  78. apAuthor.setName(wmUser.getName());
  79. apAuthor.setType(AdminConstans.AUTHOR_TYPE);
  80. apAuthor.setCreatedTime(new Date());
  81. apAuthor.setUserId(apUserId);
  82. articleFeign.save(apAuthor);
  83. }
  84. }
  85. /**
  86. * 状态监测
  87. * @param status
  88. * @return
  89. */
  90. private boolean statusCheck(Short status) {
  91. if (status == null
  92. || ( !status.equals(AdminConstans.FAIL_AUTH)
  93. && !status.equals(AdminConstans.PASS_AUTH))) {
  94. return true;
  95. }
  96. return false;
  97. }

3.8 用户审核控制层

修改ApUserRealnameController类,新增方法

  1. @PostMapping("/authPass")
  2. @Override
  3. public ResponseResult authPass(@RequestBody AuthDto dto) {
  4. return userRealnameService.updateStatusById(dto, AdminConstans.PASS_AUTH);
  5. }
  6. @PostMapping("/authFail")
  7. @Override
  8. public ResponseResult authFail(@RequestBody AuthDto dto) {
  9. return userRealnameService.updateStatusById(dto, AdminConstans.FAIL_AUTH);
  10. }

3.9 测试

步骤:

(1)修改网关配置

在heima-leadnews-admin-gateway模块中的application.yml文件中新增以下配置

  1. - id: user
  2. uri: lb://leadnews-user
  3. predicates:
  4. - Path=/user/**
  5. filters:
  6. - StripPrefix= 1

第三章 用户认证 - 图14

(2)数据准备

在leadnews-user库中ap_user表中新增一条数据

第三章 用户认证 - 图15

ap_user_realname表中新增一条数据,注意user_id字段要与ap_user表中对应

第三章 用户认证 - 图16

(3)启动工程清单

  • nacos
  • heima-leadnews-admin
  • heima-leadnews-admin-gateway
  • heima-leadnews-article
  • heima-leadnews-user
  • heima-leadnews-wemedia

(4)post测试或打开前端页面测试

第一:登录操作

url:http://localhost:6001/admin/login/in

param:{"name":"guest","password":"guest"}

第三章 用户认证 - 图17

第二,用户审核通过操作

url:http://localhost:6001/user/api/v1/auth/authPass

param:{"id":5,"status":9}

第三章 用户认证 - 图18

请求完成以后在leadnews_wemedia库中的wm_user表中新增了一条自媒体用户数据

第三章 用户认证 - 图19

在leadnews_article库中的ap_author表中新增了一条作者数据

第三章 用户认证 - 图20