java 黑马头条 day2 登录鉴权_实名认证

1 常见的加密方式回顾

2 登录认证jwt介绍

2.1 token认证

随着 Restful API、微服务的兴起,基于 Token 的认证现在已经越来越普遍。基于token的用户认证是一种服务端无状态的认证方式,所谓服务端无状态指的token本身包含登录用户所有的相关数据,而客户端在认证后的每次请求都会携带token,因此服务器端无需存放token数据。

当用户认证后,服务端生成一个token发给客户端,客户端可以放到 cookie 或 localStorage 等存储中,每次请求时带上 token,服务端收到token通过验证后即可确认用户身份。

2.2 什么是JWT?

我们现在了解了基于token认证的交互机制,但令牌里面究竟是什么内容?什么格式呢?市面上基于token的认证方式大都采用的是JWT(Json Web Token)。

JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。

JWT令牌结构:

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

  • Header

头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC、SHA256或RSA)。

一个例子:

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

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

  • Payload

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

{
    "sub": "1234567890",
    "name": "456",
    "admin": true,
    "id": 123
}

最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分。

  • Signature

第三部分是签名,此部分用于防止jwt内容被篡改。 这个部分使用base64url将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明 签名算法进行签名。 一个例子:

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

base64UrlEncode(header):jwt令牌的第一部分。 base64UrlEncode(payload):jwt令牌的第二部分。 secret:签名所使用的密钥。

下图中包含一个生成的jwt令牌:

2.3 生成token

需要引入jwt相关依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
</dependency>

工具类

package com.heima.utils.common;
​
import io.jsonwebtoken.*;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
​
public class AppJwtUtil {
    // TOKEN的有效期一天(S)
    private static final int TOKEN_TIME_OUT = 3_600;
    // 加密KEY
    private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";
    // 最小刷新间隔(S)
    private static final int REFRESH_TIME = 300;
    // 生产ID
    public static String getToken(Long id){
        Map<String, Object> claimMaps = new HashMap<>();
        claimMaps.put("id",id);
        long currentTime = System.currentTimeMillis();
        return Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date(currentTime))  //签发时间
                .setSubject("system")  //说明
                .setIssuer("heima") //签发者信息
                .setAudience("app")  //接收用户
                .compressWith(CompressionCodecs.GZIP)  //数据压缩方式
                .signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式
                .setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000))  //过期时间戳
                .addClaims(claimMaps) //cla信息
                .compact();
    }
    /**
     * 获取token中的claims信息
     * @param token
     * @return
     */
    private static Jws<Claims> getJws(String token) {
            return Jwts.parser()
                    .setSigningKey(generalKey())
                    .parseClaimsJws(token);
    }
    /**
     * 获取payload body信息
     * @param token
     * @return
     */
    public static Claims getClaimsBody(String token) {
        try {
            return getJws(token).getBody();
        }catch (ExpiredJwtException e){
            return null;
        }
    }
    /**
     * 获取hearder body信息
     * @param token
     * @return
     */
    public static JwsHeader getHeaderBody(String token) {
        return getJws(token).getHeader();
    }
    /**
     * 是否过期
     * @param claims
     * @return -1:有效,0:有效,1:过期,2:过期
     */
    public static int verifyToken(Claims claims) {
        if(claims==null){
            return 1;
        }
        try {
            claims.getExpiration()
                    .before(new Date());
            // 需要自动刷新TOKEN
            if((claims.getExpiration().getTime()-System.currentTimeMillis())>REFRESH_TIME*1000){
                return -1;
            }else {
                return 0;
            }
        } catch (ExpiredJwtException ex) {
            return 1;
        }catch (Exception e){
            return 2;
        }
    }
    /**
     * 由字符串生成加密key
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
}

测试token生成与解析

public static void main(String[] args) {
        String token = AppJwtUtil.getToken(1L);
        System.out.println(token); // 生成token
        try {
            Claims claimsBody = getClaimsBody(token); // 解析token 载荷信息
            int i = verifyToken(claimsBody); // 校验是否过期
            if(i<1){ // -1:有效,0:有效,1:过期,2:过期
                Object id = claimsBody.get("id"); // 获取载荷中存储的用户id
                System.out.println("解析token成功 ==> 用户的id值 == "+ id);
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("解析token失败");
        }
    }

3 admin端-登录实现

 

对应实体类

package com.heima.model.admin.pojos;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
 * <p>
 * 管理员用户信息表
 * </p>
 * @author itheima
 */
@Data
@TableName("ad_user")
public class AdUser{
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    /**
     * 登录用户名
     */
    @TableField("name")
    private String name;
    /**
     * 登录密码
     */
    @TableField("password")
    private String password;
    /**
     * 盐
     */
    @TableField("salt")
    private String salt;
​
    /**
     * 昵称
     */
    @TableField("nickname")
    private String nickname;
​
    /**
     * 头像
     */
    @TableField("image")
    private String image;
​
    /**
     * 手机号
     */
    @TableField("phone")
    private String phone;
    /**
     * 状态
            0 暂时不可用
            1 永久不可用
            9 正常可用
     */
    @TableField("status")
    private Integer status;
    /**
     * 邮箱
     */
    @TableField("email")
    private String email;
    /**
     * 最后一次登录时间
     */
    @TableField("login_time")
    private Date loginTime;
    /**
     * 创建时间
     */
    @TableField("created_time")
    private Date createdTime;
}

思路分析:

  1. 检查用户是否存在

  2. 检查密码是否正确

  3. 检查用户状态是否有效

  4. 修改最近登录时间

  5. 颁发token

3.1 接口定义

接口地址:/login/in

请求方式:POST

请求数据类型:application/json

响应数据类型:application/json

接口描述: Admin端登录接口

请求示例:

{
    "name": "",
    "password": ""
}

请求参数:

参数名称参数说明in是否必须数据类型schema
dtodtobodytrueAdUserDtoAdUserDto
  name用户名truestring
  password密码truestring

响应结果:

{
    "code":"状态码",
    "errorMessage":"提示信息",
    "data": {
        "token":"颁发访问凭证",
        "user": { // 登录用户信息
            
        }
    }
}

AdUserDTO

package com.heima.model.admin.dtos;
import lombok.Data;
@Data
public class AdUserDTO {
    //用户名
    private String name;
    //密码
    private String password;
}

3.2 mapper

package com.heima.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.admin.pojos.AdUser;
public interface AdUserMapper extends BaseMapper<AdUser> {
}

3.3 业务层代码

package com.heima.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.admin.dtos.AdUserDTO;
import com.heima.model.admin.pojos.AdUser;
import com.heima.model.common.dtos.ResponseResult;
public interface AdUserService extends IService<AdUser> {
    /**
     * 登录功能
     * @param DTO
     * @return
     */
    ResponseResult login(AdUserDTO DTO);
}

实现类:

@Service
public class AdUserServiceImpl extends ServiceImpl<AdUserMapper, AdUser> implements AdUserService {
    /**
     * admin 登录
     * @param dto
     * @return
     */
    @Override
    public ResponseResult login(AdUserDTO dto) {
        //1 参数校验
        if (StringUtils.isBlank(dto.getName()) || StringUtils.isBlank(dto.getPassword())) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"参数错误");
        }
        //2 根据用户名查询用户信息
        AdUser adUser = getOne(Wrappers.<AdUser>lambdaQuery()
                .eq(AdUser::getName, dto.getName() )
            );
        if (adUser == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"用户名或密码错误");
        }
       if(9 != adUser.getStatus().intValue()){
            CustException.cust(AppHttpCodeEnum.LOGIN_STATUS_ERROR,"用户状态异常,请联系管理员");
        }
        //3 获取数据库密码和盐, 匹配密码
        String dbPwd = adUser.getPassword(); // 数据库密码(加密)
        String salt = adUser.getSalt();
        // 用户输入密码(加密后)
        String newPwd = DigestUtils.md5DigestAsHex((dto.getPassword() + salt).getBytes());
        if (!dbPwd.equals(newPwd)) {
            CustException.cust(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR,"用户名或密码错误");
        }
        //4 修改登录时间
        adUser.setLoginTime(new Date());
        updateById(adUser);
        //5 颁发token jwt 令牌
        String token = AppJwtUtil.getToken(adUser.getId().longValue());
        // 用户信息返回 VO
        AdUserVO userVO = new AdUserVO();
        BeanUtils.copyProperties(adUser, userVO);
        //6 返回结果(jwt)
        Map map = new HashMap();
        map.put("token", token);
        map.put("user", userVO);
        return ResponseResult.okResult(map);
    }
}

封装vo对象,返回登录用户信息

package com.heima.model.admin.vo;
​
import lombok.Data;
import java.util.Date;
​
@Data
public class AdUserVO {
    private Integer id;
    private String name;
    private String nickname;
    private String image;
    private String email;
    private Date loginTime;
    private Date createdTime;
}

3.4 控制层代码

@Api(value = "运营平台登录API",tags = "运营平台登录API")
@RestController
@RequestMapping("/login")
public class LoginController{
    @Autowired
    AdUserService userService;
    @ApiOperation("登录")
    @PostMapping("/in")
    public ResponseResult login(@RequestBody AdUserDTO DTO) {
        return userService.login(DTO);
    }
}

3.5 测试

在表中创建一个用户guest,使用以下代码生成密码后修改表中的密码

String salt = "123456";
String pswd = "guest"+salt;
String saltPswd = DigestUtils.md5DigestAsHex(pswd.getBytes());
System.out.println(saltPswd);
//34e20b52f5bd120db806e57e27f47ed0

生成密码后的结果为:

salt:123456

password: 34e20b52f5bd120db806e57e27f47ed0

username:guest

 

 

4 网关校验jwt

4.1 全局过滤器实现jwt校验

思路分析:

  1. 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录

  2. 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户

  3. 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN

  4. 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误

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

第一步,准备工具类

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

 

第二步,编写全局过滤器

package com.heima.gateway.filter;
import com.alibaba.fastjson.JSON;
import com.heima.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
​
import java.util.*;
/**
 * @Description: 认证过滤器
 * @Version: V1.0
 */
@Component
@Slf4j
@Order(0) // 值越小越优先执行
public class AuthorizeFilter implements GlobalFilter {
  private static List<String> urlList = new ArrayList<>();
  // 初始化白名单 url路径
  static {
    urlList.add("/login/in");
    urlList.add("/v2/api-docs");
  }
  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    //1 判断当前是否是登录请求,如果是登录则放行
    ServerHttpRequest request = exchange.getRequest();
    String reqUrl = request.getURI().getPath();
    for (String url : urlList) {
      if (reqUrl.contains(url)) {
        return chain.filter(exchange);
      }
    }
    //2 获取请求头jwt token信息
    String jwtToken = request.getHeaders().getFirst("token");
    if(StringUtils.isBlank(jwtToken)){
      //如果不存在,向客户端返回错误提示信息
      return writeMessage(exchange, "需要登录");
    }
    //3 判断令牌信息是否正确
    try {
      Claims claims = AppJwtUtil.getClaimsBody(jwtToken);
      //  -1:有效,0:有效,1:过期,2:过期
      int verifyToken = AppJwtUtil.verifyToken(claims);
      //3.1 如果不存在或失效,则拦截
      if (verifyToken > 0) {
        return writeMessage(exchange, "认证失效,请重新登录");
      }
      //3.2 解析JWT令牌信息
      Integer id = claims.get("id", Integer.class);
      log.info("token网关校验成功   id:{},    URL:{}", id, request.getURI().getPath());
      //***4 将令牌信息传递到对应的微服务
      request.mutate().header("userId", String.valueOf(id));
      //5 返回结果
      return chain.filter(exchange);
    } catch (Exception e) {
      log.error("token 校验失败 :{}", e);
      return writeMessage(exchange, "认证失效,请重新登录");
    }
  }
  /**
     * 返回错误提示信息
     * @return
     */
  private Mono<Void> writeMessage(ServerWebExchange exchange, String message) {
    Map<String, Object> map = new HashMap<>();
    map.put("code", HttpStatus.UNAUTHORIZED.value());
    map.put("errorMessage", message);
    //获取响应对象
    ServerHttpResponse response = exchange.getResponse();
    //设置状态码
    response.setStatusCode(HttpStatus.UNAUTHORIZED);
    //response.setStatusCode(HttpStatus.OK);
    //设置返回类型
    response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
    //设置返回数据
    DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONBytes(map));
    //响应数据回浏览器
    return response.writeWith(Flux.just(buffer));
  }
}

上面api中语法大家可能会感觉陌生,这是因为Gateway 采用的是基于webFlux异步非阻塞的网络处理框架,api的设计和传统SpringMVC的api大不相同, WebFlux技术比较新,目前使用还没有那么普及 所以上面代码不要求掌握, 作用理解即可。

Spring WebFlux 入门 - 废物大师兄 - 博客园

 

第二步,编写全局过滤器

package com.heima.gateway.filter;
import com.alibaba.fastjson.JSON;
import com.heima.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
​
import java.util.*;
/**
 * @Description: 认证过滤器
 * @Version: V1.0
 */
@Component
@Slf4j
@Order(0) // 值越小越优先执行
public class AuthorizeFilter implements GlobalFilter {
  private static List<String> urlList = new ArrayList<>();
  // 初始化白名单 url路径
  static {
    urlList.add("/login/in");
    urlList.add("/v2/api-docs");
  }
  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    //1 判断当前是否是登录请求,如果是登录则放行
    ServerHttpRequest request = exchange.getRequest();
    String reqUrl = request.getURI().getPath();
    for (String url : urlList) {
      if (reqUrl.contains(url)) {
        return chain.filter(exchange);
      }
    }
    //2 获取请求头jwt token信息
    String jwtToken = request.getHeaders().getFirst("token");
    if(StringUtils.isBlank(jwtToken)){
      //如果不存在,向客户端返回错误提示信息
      return writeMessage(exchange, "需要登录");
    }
    //3 判断令牌信息是否正确
    try {
      Claims claims = AppJwtUtil.getClaimsBody(jwtToken);
      //  -1:有效,0:有效,1:过期,2:过期
      int verifyToken = AppJwtUtil.verifyToken(claims);
      //3.1 如果不存在或失效,则拦截
      if (verifyToken > 0) {
        return writeMessage(exchange, "认证失效,请重新登录");
      }
      //3.2 解析JWT令牌信息
      Integer id = claims.get("id", Integer.class);
      log.info("token网关校验成功   id:{},    URL:{}", id, request.getURI().getPath());
      //***4 将令牌信息传递到对应的微服务
      request.mutate().header("userId", String.valueOf(id));
      //5 返回结果
      return chain.filter(exchange);
    } catch (Exception e) {
      log.error("token 校验失败 :{}", e);
      return writeMessage(exchange, "认证失效,请重新登录");
    }
  }
  /**
     * 返回错误提示信息
     * @return
     */
  private Mono<Void> writeMessage(ServerWebExchange exchange, String message) {
    Map<String, Object> map = new HashMap<>();
    map.put("code", HttpStatus.UNAUTHORIZED.value());
    map.put("errorMessage", message);
    //获取响应对象
    ServerHttpResponse response = exchange.getResponse();
    //设置状态码
    response.setStatusCode(HttpStatus.UNAUTHORIZED);
    //response.setStatusCode(HttpStatus.OK);
    //设置返回类型
    response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
    //设置返回数据
    DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONBytes(map));
    //响应数据回浏览器
    return response.writeWith(Flux.just(buffer));
  }
}

上面api中语法大家可能会感觉陌生,这是因为Gateway 采用的是基于webFlux异步非阻塞的网络处理框架,api的设计和传统SpringMVC的api大不相同, WebFlux技术比较新,目前使用还没有那么普及 所以上面代码不要求掌握, 作用理解即可。

https://www.cnblogs.com/cjsblog/p/12580518.html

4.2 网关token校验测试

启动admin服务,通过网关访问admin,会提示需要认证才能访问,这个时候需要在heads中设置设置token才能正常访问。

 

 

5 app端用户认证列表查询

5.1 需求分析

当用户在app前端进行了认证

 

对应的实体类:

package com.heima.model.user.pojos;
​
/**
 * <p>
 * APP实名认证信息表
 * </p>
 *
 * @author itheima
 */
@Data
@TableName("ap_user_realname")
public class ApUserRealname implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    /**
     * 账号ID
     */
    @TableField("user_id")
    private Integer userId;
    /**
     * 用户名称
     */
    @TableField("name")
    private String name;
    /**
     * 资源名称
     */
    @TableField("idno")
    private String idno;
    /**
     * 正面照片
     */
    @TableField("font_image")
    private String fontImage;
    /**
     * 背面照片
     */
    @TableField("back_image")
    private String backImage;
    /**
     * 手持照片
     */
    @TableField("hold_image")
    private String holdImage;
    /**
     * 活体照片
     */
    @TableField("live_image")
    private String liveImage;
    /**
     * 状态
            0 创建中
            1 待审核
            2 审核失败
            9 审核通过
     */
    @TableField("status")
    private Short status;
    /**
     * 拒绝原因
     */
    @TableField("reason")
    private String reason;
    /**
     * 创建时间
     */
    @TableField("created_time")
    private Date createdTime;
    /**
     * 提交时间
     */
    @TableField("submited_time")
    private Date submitedTime;
    /**
     * 更新时间
     */
    @TableField("updated_time")
    private Date updatedTime;
​
}

5.2 新建user微服务

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

  • 定义包名

  • 新建引导类 参考其他微服务创建

  • pom文件引入,参考其他微服务

(3)在resources下新建bootstrap.yml

spring:
  application:
    name: leadnews-user # 服务名称
  profiles:
    active: dev # 开发环境配置
    ip: 192.168.200.130  # 环境ip地址
  cloud:
    nacos:
      server-addr: ${spring.profiles.ip}:8848
      discovery: # 注册中心地址配置
        namespace: ${spring.profiles.active}
      config: # 配置中心地址配置
        namespace: ${spring.profiles.active}
        file-extension: yml # data-id 后缀
        name: ${spring.application.name} # data-id名称
        shared-configs: # 共享配置
          - data-id: share-feign.yml # 配置文件名-Data Id
            group: DEFAULT_GROUP   # 默认为DEFAULT_GROUP
            refresh: false   # 是否动态刷新,默认为false

(4)在配置中心nacos中 新建 leadnews-user.yml配置

server:
  port: 9002
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${spring.profiles.ip}:3306/leadnews_user?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.heima.model.user.pojos

5.3 接口定义

接口地址:/api/v1/auth/list

请求方式:POST

请求数据类型:application/json

响应数据类型:*/*

接口描述:

请求示例:

{
    "id": 0,
    "msg": "",
    "page": 0,
    "size": 0,
    "status": 0
}

请求参数:

参数名称参数说明in是否必须数据类型schema
AuthDtodtobodytrueAuthDtoAuthDto
  page当前第几页falseinteger(int32)
  size每页显示条数falseinteger(int32)
  status用户状态falseinteger(int32)

AuthDTO

package com.heima.model.user.dtos;
​
import com.heima.model.common.dtos.PageRequestDTO;
import lombok.Data;
​
@Data
public class AuthDTO extends PageRequestDTO {
    //状态
    private Short status;
    // 认证用户ID
    private Integer id;
    //驳回的信息
    private String msg;
}

5.4 mapper

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

package com.heima.user.mapper;
​
public interface ApUserRealnameMapper extends BaseMapper<ApUserRealname> {
}

5.5 业务层

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

package com.heima.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.user.dtos.AuthDTO;
import com.heima.model.user.pojos.ApUserRealname;
public interface ApUserRealnameService extends IService<ApUserRealname> {
    /**
     * 根据状态查询需要认证相关的用户信息
     * @param DTO
     * @return
     */
    ResponseResult loadListByStatus(AuthDTO DTO);
}

实现类:

package com.heima.user.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.AuthDTO;
import com.heima.model.user.pojos.ApUserRealname;
import com.heima.user.mapper.ApUserRealnameMapper;
import com.heima.user.service.ApUserRealnameService;
import org.springframework.stereotype.Service;
@Service
public class ApUserRealnameServiceImpl extends ServiceImpl<ApUserRealnameMapper, ApUserRealname> implements ApUserRealnameService {
    /**
     * 查询列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult loadListByStatus(AuthDTO dto) {
        // 1 参数检查
        if (dto == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();
​
        // 2 条件查询
        Page<ApUserRealname> page = new Page<>(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<ApUserRealname> lambdaQueryWrapper = new LambdaQueryWrapper();
​
        if (dto.getStatus() != null) {
            lambdaQueryWrapper.eq(ApUserRealname::getStatus, dto.getStatus());
        }
​
        IPage<ApUserRealname> resultPage = page(page, lambdaQueryWrapper);
​
        // 3 返回结果
        return new PageResponseResult(dto.getPage(), dto.getSize(),
                resultPage.getTotal(), resultPage.getRecords());
    }
}

5.6 控制层

package com.heima.user.controller.v1;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.user.dtos.AuthDTO;
import com.heima.user.service.ApUserRealnameService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
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;
@Api(value = "app用户实名认证API",tags = "app用户实名认证API")
@RestController
@RequestMapping("/api/v1/auth")
public class ApUserRealnameController {
    @Autowired
    private ApUserRealnameService userRealnameService;
    @ApiOperation("根据状态查询实名认证列表")
    @PostMapping("/list")
    public ResponseResult loadListByStatus(@RequestBody AuthDTO dto){
        return userRealnameService.loadListByStatus(dto);
    }
}

5.7 测试

http://localhost:9002/doc.html

6 app端用户认证后审核

6.1 需求分析

 

 

  • 在app端的个人中心用户可以实名认证,需要材料为:姓名、身份证号、身份证正面照、身份证反面照、手持照片、活体照片(通过微笑、眨眼、张嘴、摇头、点头等组合动作,确保操作的为真实活体人脸。),当用户提交审核后就到了后端让运营管理人员进行审核

  • 平台运营端查看用户认证信息,进行审核,其中审核包括了用户身份审核,需要对接公安系统校验身份证信息

  • 用户通过审核后需要开通自媒体账号(该账号的用户名和密码与app一致)

  • 用户通过审核后需要在article中在作者表中新建一个作者信息

6.1.1 实现步骤

三个角色(用户、自媒体、作者)对应的表分析:

  • ap_user:用户表。普通阅读文章的用户。不发表文章可以不用实名认证。

  • ap_user_realname:用户认证信息表。存放实名认证的用户信息,审核通过后可以发表文章数据。

  • wm_user:自媒体用户信息表

  • ap_author:文章作者信息表

 

 

  1. admin后台点击审核按钮审核当前用户,传递ap_user_realname的id

  2. user微服务接收到审核用户请求,按照资质条件审核

  3. 如果审核通过则保存用户认证信息数据到ap_user_realname中

  4. 再通过feign远程的调用wemedia微服务的新增自媒体用户接口,完成新增自媒体信息保存,(该账号的用户名和密码与app一致)

  5. 再通过feign远程的调用article微服务的新增文章作者的接口,完成新增文章作者信息保存

  6. 前端响应审核成功

6.2 自媒体服务-用户保存

6.2.1 wemedia微服务搭建

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

(2)resources下新建bootstrap.yml

spring:
  application:
    name: leadnews-wemedia # 服务名称
  profiles:
    active: dev # 开发环境配置
    ip: 192.168.200.130  # 环境ip地址
  cloud:
    nacos:
      server-addr: ${spring.profiles.ip}:8848
      discovery: # 注册中心地址配置
        namespace: ${spring.profiles.active}
      config: # 配置中心地址配置
        namespace: ${spring.profiles.active}
        file-extension: yml # data-id 后缀
        name: ${spring.application.name} # data-id名称
        shared-configs: # 共享配置
          - data-id: share-feign.yml # 配置文件名-Data Id
            group: DEFAULT_GROUP   # 默认为DEFAULT_GROUP
            refresh: false   # 是否动态刷新,默认为false

(3)配置中心nacos创建leadnews-wemedia.yml配置

server:
  port: 9004
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${spring.profiles.ip}:3306/leadnews_wemedia?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.heima.model.media.pojos

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

wm_user 自媒体用户表

 

实体类:

package com.heima.model.wemedia.pojos;
/**
 * <p>
 * 自媒体用户信息表
 * </p>
 *
 * @author itheima
 */
@Data
@TableName("wm_user")
public class WmUser implements Serializable {
​
    private static final long serialVersionUID = 1L;
​
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
​
    @TableField("ap_user_id")
    private Integer apUserId;
​
    /**
     * 登录用户名
     */
    @TableField("name")
    private String name;
​
    /**
     * 登录密码
     */
    @TableField("password")
    private String password;
​
    /**
     * 盐
     */
    @TableField("salt")
    private String salt;
​
    /**
     * 昵称
     */
    @TableField("nickname")
    private String nickname;
​
    /**
     * 头像
     */
    @TableField("image")
    private String image;
​
    /**
     * 归属地
     */
    @TableField("location")
    private String location;
​
    /**
     * 手机号
     */
    @TableField("phone")
    private String phone;
​
    /**
     * 状态
            0 暂时不可用
            1 永久不可用
            9 正常可用
     */
    @TableField("status")
    private Integer status;
​
    /**
     * 邮箱
     */
    @TableField("email")
    private String email;
​
    /**
     * 账号类型
            0 个人 
            1 企业
            2 子账号
     */
    @TableField("type")
    private Integer type;
​
    /**
     * 运营评分
     */
    @TableField("score")
    private Integer score;
​
    /**
     * 最后一次登录时间
     */
    @TableField("login_time")
    private Date loginTime;
​
    /**
     * 创建时间
     */
    @TableField("created_time")
    private Date createdTime;
​
}

(1)接口定义

接口描述: 根据用户名查询自媒体用户

接口地址:/api/v1/user/findByName/{name}

请求方式:GET

请求数据类型:*

响应数据类型:*/*

请求参数:

参数名称参数说明in是否必须数据类型schema
namenamepathtruestring

接口描述: 保存自媒体用户

接口地址:/api/v1/user/save

请求方式:POST

请求数据类型:application/json

响应数据类型:*/*

请求示例:

{
    "apAuthorId": 0,
    "apUserId": 0,
    "createdTime": "",
    "email": "",
  .....  # 其他参数省略
}

请求参数:

参数名称参数说明in是否必须数据类型schema
wmUserwmUserbodytrueWmUserWmUser
  apAuthorIdfalseinteger(int32)

(2)mapper定义

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

package com.heima.wemedia.mapper;
public interface WmUserMapper extends BaseMapper<WmUser> {
}

(3)业务层

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

package com.heima.wemedia.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.wemedia.pojos.WmUser;
public interface WmUserService extends IService<WmUser> {
}

实现类:

package com.heima.wemedia.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmUserService;
import org.springframework.stereotype.Service;
@Service
public class WmUserServiceImpl extends ServiceImpl<WmUserMapper, WmUser> implements WmUserService {
}

(4)控制层

package com.heima.wemedia.controller.v1;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.wemedia.service.WmUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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;
/**
 * @Description:
 * @Version: V1.0
 */
@Api(value = "自媒体用户API",tags = "自媒体用户API")
@RestController
@RequestMapping("/api/v1/user")
public class WmUserController {
    @Autowired
    private WmUserService wmUserService;
    @ApiOperation("保存自媒体用户信息")
    @PostMapping("/save")
    public ResponseResult<WmUser> save(@RequestBody WmUser wmUser) {
        wmUserService.save(wmUser);
        return ResponseResult.okResult(wmUser);
    }
    @ApiOperation("根据名称查询自媒体用户信息")
    @GetMapping("/findByName/{name}")
    public ResponseResult<WmUser> findByName(@PathVariable("name") String name) {
        return ResponseResult.okResult(wmUserService.getOne(Wrappers.<WmUser>lambdaQuery().eq(WmUser::getName, name)));
    }
}

访问http://127.0.0.1:9004/doc.html测试

 

6.2.3 feign远程接口定义

新建模块 heima-leadnews-feign,主要存放所有的远程访问的接口,并且实现自动化的配置。

(1)引入依赖

<dependencies>
    <dependency>
        <groupId>com.heima</groupId>
        <artifactId>heima-leadnews-model</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <!--openfeign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
</dependencies>

(2)新建包com.heima.feigns,定义WemediaFeign接口

package com.heima.feigns;
import com.heima.config.HeimaFeignAutoConfiguration;
import com.heima.feigns.fallback.WemediaFeignFallback;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmUser;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(
        value = "leadnews-wemedia",
        fallbackFactory = WemediaFeignFallback.class,
        configuration = HeimaFeignAutoConfiguration.class
)
public interface WemediaFeign {
    @PostMapping("/api/v1/user/save")
    public ResponseResult<WmUser> save(@RequestBody WmUser wmUser);
    @GetMapping("/api/v1/user/findByName/{name}")
    public ResponseResult<WmUser> findByName(@PathVariable("name") String name);
}

(3)新建 com.heima.config包,并创建HeimaFeignAutoConfiguration配置类

package com.heima.config;
import feign.Logger;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableFeignClients(basePackages = "com.heima.feigns")
@ComponentScan("com.heima.feigns.fallback")
public class HeimaFeignAutoConfiguration {
    @Bean
    Logger.Level level(){
        return Logger.Level.FULL;
    }
}

(4) 在com.heima.feigns.fallback 包创建 WemediaFeignFallback 服务降级类

package com.heima.feigns.fallback;
import com.heima.feigns.WemediaFeign;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmUser;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class WemediaFeignFallback implements FallbackFactory<WemediaFeign> {
    @Override
    public WemediaFeign create(Throwable throwable) {
        return new WemediaFeign() {
            @Override
            public ResponseResult<WmUser> save(WmUser wmUser) {
                log.error("参数: {}",wmUser);
                log.error("自媒体 save 远程调用出错啦 ~~~ !!!! {} ",throwable.getMessage());
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
            }
            @Override
            public ResponseResult<WmUser> findByName(String name) {
                log.error("参数: {}",name);
                log.error("自媒体 findByName 远程调用出错啦 ~~~ !!!! {} ",throwable.getMessage());
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
            }
        };
    }
}

(5)在resources目录下创建 META-INF 文件夹,并新建 spring.factories 文件

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.heima.config.HeimaFeignAutoConfiguration

(6) 在services聚合工程中引入Feign的起步依赖

        <!-- 统一feign远程调用依赖 引入后可以直接注入feign接口-->
        <dependency>
            <artifactId>heima-leadnews-feign</artifactId>
            <groupId>com.heima</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

6.3 文章服务-创建作者

6.3.1 article微服务创建

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

(2)resources下新建bootstrap.yml

spring:
  application:
    name: leadnews-article # 服务名称
  profiles:
    active: dev # 开发环境配置
    ip: 192.168.200.130  # 环境ip地址
  cloud:
    nacos:
      discovery: # 注册中心地址配置
        server-addr: ${spring.profiles.ip}:8848
        namespace: ${spring.profiles.active}
      config: # 配置中心地址配置
        server-addr: ${spring.profiles.ip}:8848
        namespace: ${spring.profiles.active}
        file-extension: yml # data-id 后缀
        name: ${spring.application.name} # data-id名称
        shared-configs: # 共享配置
          - data-id: share-feign.yml # 配置文件名-Data Id
            group: DEFAULT_GROUP   # 默认为DEFAULT_GROUP
            refresh: false   # 是否动态刷新,默认为false

(3) 配置中心nacos中创建配置 leadnews-article.yml

server:
  port: 9003
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${spring.profiles.ip}:3306/leadnews_article?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.heima.model.article.pojos

6.3.2 查询作者和保存作者

ap_author 作者信息表

 

(1) 接口定义

接口描述: 根据ApUser id查询作者信息

接口地址:/api/v1/author/findByUserId/{id}

请求方式:GET

请求数据类型:*

响应数据类型:*/*

请求参数:

参数名称参数说明in是否必须数据类型schema
ididpathtrueinteger(int32)

响应参数:

参数名称参数说明类型schema
createdTimestring(date-time)string(date-time)
idinteger(int32)integer(int32)
namestring
typeinteger(int32)integer(int32)
userIdinteger(int32)integer(int32)
wmUserIdinteger(int32)integer(int32)

响应示例:

{
    "createdTime": "",
    "id": 0,
    "name": "",
    "type": 0,
    "userId": 0,
    "wmUserId": 0
}

接口描述: 保存作者信息

接口地址:/api/v1/author/save

请求方式:POST

请求数据类型:application/json

响应数据类型:*/*

请求示例:

{
    "createdTime": "",
    "id": 0,
    "name": "",
    "type": 0,
    "userId": 0,
    "wmUserId": 0
}

请求参数:

参数名称参数说明in是否必须数据类型schema
apAuthorapAuthorbodytrueApAuthorApAuthor
  createdTimefalsestring(date-time)
  idfalseinteger(int32)
  namefalsestring
  typefalseinteger(int32)
  userIdfalseinteger(int32)
  wmUserIdfalseinteger(int32)

(2)mapper接口

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

package com.heima.article.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.article.pojos.ApAuthor;
public interface AuthorMapper extends BaseMapper<ApAuthor> {
}

(3)业务层

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

package com.heima.article.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.article.pojos.ApAuthor;

public interface AuthorService extends IService<ApAuthor> {
}

实现类:

package com.heima.article.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.AuthorMapper;
import com.heima.article.service.AuthorService;
import com.heima.model.article.pojos.ApAuthor;
import org.springframework.stereotype.Service;

@Service
public class AuthorServiceImpl extends ServiceImpl<AuthorMapper, ApAuthor> implements AuthorService {
}

(4) 控制层

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

package com.heima.article.controller.v1;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.article.service.AuthorService;
import com.heima.model.article.pojos.ApAuthor;
import com.heima.model.common.dtos.ResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Api(value = "app作者管理API",tags = "app作者管理API")
@RestController
@RequestMapping("/api/v1/author")
public class AuthorController{
    @Autowired
    private AuthorService authorService;
    @ApiOperation(value = "查询作者",notes = "根据appUserId查询关联作者信息")
    @GetMapping("/findByUserId/{userId}")
    public ResponseResult<ApAuthor> findByUserId(@PathVariable("userId") Integer userId) {
        return ResponseResult.okResult(authorService.getOne(Wrappers.<ApAuthor>lambdaQuery().eq(ApAuthor::getUserId, userId)));
    }
    @ApiOperation(value = "保存作者",notes = "保存作者信息")
    @PostMapping("/save")
    public ResponseResult save(@RequestBody ApAuthor apAuthor) {
        authorService.save(apAuthor);
        return ResponseResult.okResult();
    }
}

访问http://127.0.0.1:9003/doc.html测试

6.4 用户服务-认证审核用户

6.4.1 用户审核接口定义

接口描述: 自媒体用户审核(通过/不通过)

接口地址1:/api/v1/auth/authFail

接口地址2:/api/v1/auth/authPass

请求方式:POST

请求数据类型:application/json

响应数据类型:application/json

请求示例:

{
    "id": 0,
    "msg": ""
}

请求参数:

参数名称参数说明in是否必须数据类型schema
dtodtobodytrueAuthDtoAuthDto
  idfalseinteger(int32)
  msgfalsestring
   statusfalseinteger(int32)

6.4.2 用户审核mapper接口定义

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

app端用户信息表

 

heima-leadnews-model中新增实体类

package com.heima.model.user.pojos;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * <p>
 * APP用户信息表
 * </p>
 * @author itheima
 */
@Data
@TableName("ap_user")
public class ApUser implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    /**
     * 密码、通信等加密盐
     */
    @TableField("salt")
    private String salt;
    /**
     * 用户名
     */
    @TableField("name")
    private String name;
    /**
     * 密码,md5加密
     */
    @TableField("password")
    private String password;
​
    /**
     * 手机号
     */
    @TableField("phone")
    private String phone;
​
    /**
     * 头像
     */
    @TableField("image")
    private String image;
​
    /**
     * 0 男
            1 女
            2 未知
     */
    @TableField("sex")
    private Boolean sex;
​
    /**
     * 0 未
            1 是
     */
    @TableField("is_certification")
    private Boolean certification;
​
    /**
     * 是否身份认证
     */
    @TableField("is_identity_authentication")
    private Boolean identityAuthentication;
​
    /**
     * 0正常
       1锁定
     */
    @TableField("status")
    private Boolean status;
​
    /**
     * 0 普通用户
            1 自媒体人
            2 大V
     */
    @TableField("flag")
    private Short flag;
​
    /**
     * 注册时间
     */
    @TableField("created_time")
    private Date createdTime;
​
}

user-service模块中新增mapper接口

package com.heima.user.mapper;
public interface ApUserMapper extends BaseMapper<ApUser> {
}

6.4.3 用户审核业务层

新建常量类:com.heima.common.constants.admin.AdminConstants

package com.heima.model.common.constants.admin;
public class AdminConstants {
    public static final Short WAIT_AUTH = 1;
    public static final Short PASS_AUTH = 9;
    public static final Short FAIL_AUTH = 2;
    public static final Integer AUTHOR_TYPE = 2; // 自媒体用户
}

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

    /**
     * 根据状态进行审核
     * @param dto
     * @param status  2 审核失败   9 审核成功
     * @return
     */
    ResponseResult updateStatusById(AuthDTO dto, Short status);

实现类:

    @Autowired
    ApUserMapper apUserMapper;
    @Autowired
    WemediaFeign wemediaFeign;
    @Autowired
    ArticleFeign articleFeign;
​
    @Override
    public ResponseResult updateStatusById(AuthDTO dto, Short status) {
        //1 参数检查
        if (dto.getId()==null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2 查询当前认证用户是否在 APP端有当前用户
        ApUserRealname apUserRealname = getOne(Wrappers.<ApUserRealname>lambdaQuery()
                .eq(ApUserRealname::getId,dto.getId())
        );
        if (apUserRealname == null) {
            log.error("待审核 实名认证信息不存在   userRealnameId:{}", dto.getId());
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
​
        if (!AdminConstants.WAIT_AUTH.equals(apUserRealname.getStatus())) {
            log.error("实名认证信息非待审核状态   userRealnameId:{}", dto.getId());
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_ALLOW);
        }
​
        ApUser apUser = apUserMapper.selectOne(Wrappers.<ApUser>lambdaQuery()
                .eq(ApUser::getId, apUserRealname.getUserId()));
        if(apUser == null){
            log.error("实名认证信息 关联 app的用户不存在    userRealnameId:{}, userId:{} ", dto.getId(), apUserRealname.getUserId());
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //3 更新认证用户信息
        apUserRealname.setStatus(status);
        apUserRealname.setUpdatedTime(new Date());
        if(StringUtils.isNotBlank(dto.getMsg())){
            apUserRealname.setReason(dto.getMsg());
        }
        updateById(apUserRealname);
​
        //4 认证状态如果为 通过
        if (AdminConstants.PASS_AUTH.equals(status)) {
            //4.1 创建自媒体账户
            WmUser wmUser = createWmUser(dto,apUser);
            //4.2 创建作者信息
            createApAuthor(wmUser);
        }
        //5 返回结果
        return ResponseResult.okResult();
    }
​
    /**
     * 4.2 创建作者信息
     * @param wmUser
     * @return
     */
    private void createApAuthor(WmUser wmUser) {
        //1 检查是否成功调用
        ResponseResult<ApAuthor> apAuthorResult = articleFeign.findByUserId(wmUser.getApUserId());
        if(apAuthorResult.getCode().intValue() != 0){
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,apAuthorResult.getErrorMessage());
        }
        //2. 检查作者信息是否已经存在
        ApAuthor apAuthor = apAuthorResult.getData();
        if (apAuthor != null) {
            CustException.cust(AppHttpCodeEnum.DATA_EXIST,"作者信息已存在");
        }
        //3. 添加作者信息
        apAuthor = new ApAuthor();
        apAuthor.setCreatedTime(new Date());
        apAuthor.setName(wmUser.getName());
        apAuthor.setType(AdminConstants.AUTHOR_TYPE); // 自媒体人类型
        apAuthor.setUserId(wmUser.getApUserId()); // APP 用户ID
        apAuthor.setWmUserId(wmUser.getId()); // 自媒体用户ID
        ResponseResult result = articleFeign.save(apAuthor);
        //4. 结果失败,抛出异常
        if (result.getCode() != 0) {
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,result.getErrorMessage());
        }
    }
    /**
     * 4.1 创建自媒体账户
     * @param dto
     * @param apUser  APP端用户
     * @return
     */
    private WmUser createWmUser(AuthDTO dto, ApUser apUser) {
        //1 查询自媒体账号是否存在(APP端用户密码和自媒体密码一致)
        ResponseResult<WmUser> wmUserResult = wemediaFeign.findByName(apUser.getName());
        if(wmUserResult.getCode().intValue() != 0){
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,wmUserResult.getErrorMessage());
        }
        WmUser wmUser =wmUserResult.getData();
        if (wmUser != null) {
            CustException.cust(AppHttpCodeEnum.DATA_EXIST,"自媒体用户信息已存在");
        }
        wmUser = new WmUser();
        wmUser.setName(apUser.getName());
        wmUser.setSalt(apUser.getSalt());  // 盐
        wmUser.setPassword(apUser.getPassword()); // 密码
        wmUser.setPhone(apUser.getPhone());
        wmUser.setCreatedTime(new Date());
        wmUser.setType(0); // 个人
        wmUser.setApUserId(apUser.getId());  // app端用户id
        wmUser.setStatus(AdminConstants.PASS_AUTH.intValue());
​
        ResponseResult<WmUser> saveResult = wemediaFeign.save(wmUser);
        if(saveResult.getCode().intValue()!=0){
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,saveResult.getErrorMessage());
        }
        return saveResult.getData();
    }

6.4.4 用户审核控制层

修改ApUserRealnameController类,新增方法

    @ApiOperation("实名认证通过")
    @PostMapping("/authPass")
    public ResponseResult authPass(@RequestBody AuthDTO DTO) {
        return userRealnameService.updateStatusById(DTO, AdminConstants.PASS_AUTH);
    }
    @ApiOperation("实名认证失败")
    @PostMapping("/authFail")
    public ResponseResult authFail(@RequestBody AuthDTO DTO) {
        return userRealnameService.updateStatusById(DTO, AdminConstants.FAIL_AUTH);
    }

6.4.5 测试

步骤:

(1)修改网关配置

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

- id: user
  uri: lb://leadnews-user
  predicates:
  - Path=/user/**
  filters:
  - StripPrefix= 1

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值