登录¶
表结构分析¶
用户相关的内容较多,可以单独设置一个库xxx_user
。
表名称 | 说明 |
---|---|
ap_user | APP用户信息表 |
ap_user_fan | APP用户粉丝信息表 |
ap_user_follow | APP用户关注信息表 |
ap_user_realname | APP实名认证信息表 |
登录需要用到的是ap_user表,表结构如下:
DROP TABLE IF EXISTS `ap_user`;
CREATE TABLE `ap_user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`salt` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码、通信等加密盐',
`name` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名',
`password` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码,md5加密',
`phone` varchar(11) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号',
`image` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
`sex` tinyint(1) unsigned DEFAULT NULL COMMENT '0 男\r\n 1 女\r\n 2 未知',
`is_certification` tinyint(1) unsigned DEFAULT NULL COMMENT '0 未\r\n 1 是',
`is_identity_authentication` tinyint(1) DEFAULT NULL COMMENT '是否身份认证',
`status` tinyint(1) unsigned DEFAULT NULL COMMENT '0正常\r\n 1锁定',
`flag` tinyint(1) unsigned DEFAULT NULL COMMENT '0 普通用户\r\n 1 自媒体人\r\n 2 大V',
`created_time` datetime DEFAULT NULL COMMENT '注册时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='APP用户信息表';
项目中的持久层使用的mybatis-plus,使用mybais-plus逆向生成对应的实体类
app_user表对应的实体类如下:
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;
}
手动加密(md5+随机字符串)¶
md5是不可逆加密,md5相同的密码每次加密都一样,不太安全。在md5的基础上手动加盐(salt)处理。
注册->生成盐¶
- 用户输入用户名+密码。
- 根据用户生成salt(一个随机字符串,例:abc)。
- 密码+salt md5加密生成password。
user表中保存的是用户名、salt、password。
登录->使用盐来配合验证¶
- 用户输入用户名+密码。
- 根据用户名在user表中查询用户的salt和password。
- 用户输入的密码+salt,md5加密和user表中的password对比,判断密码是否正确。
用户端微服务搭建¶
heima-leadnews-service依赖说明¶
<?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>heima-leadnews</artifactId>
<groupId>com.heima</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>heima-leadnews-service</artifactId>
<packaging>pom</packaging>
<modules>
<module>heima-leadnews-user</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 引入依赖模块 -->
<!-- 存放实体类和dto-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-model</artifactId>
</dependency>
<!-- 通用的配置-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-common</artifactId>
</dependency>
<!-- feign对外统一接口-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-feign-api</artifactId>
</dependency>
<!-- Spring boot starter -->
<!-- web-starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- nacos注册中心和配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
</project>
在heima-leadnews-service下创建Module工程heima-leadnews-user用户微服务。
引导类UserApplication.java
package com.heima.user;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.user.mapper")
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
}
bootstrap.yml
server:
port: 51801
spring:
application:
name: leadnews-user
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
config:
server-addr: 192.168.200.130:8848
file-extension: yml
在nacos中创建配置文件
-
Data ID:leadnews-user
-
Group:DEFAULT_GRUOP
-
配置格式:YAML
-
配置内容:
spring:
#mysql驱动
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&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
登录功能实现¶
1、接口定义¶
接口路径:/api/v1/login/login_auth
@RestController
@RequestMapping("/api/v1/login")//接口路径
public class ApUserLoginController {
@PostMapping("/login_auth")//接口路径,请求方式POST
public ResponseResult login(@RequestBody LoginDto dto) {//参数:LoginDto,响应结果:ResponseResult
return null;
}
}
LoginDto里面包含phone手机号和password密码
@Data
public class LoginDto {
/**
* 手机号
*/
private String phone;
/**
* 密码
*/
private String password;
}
2、mapper¶
package com.heima.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.user.pojos.ApUser;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ApUserMapper extends BaseMapper<ApUser> {
}
3、service¶
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.LoginDto;
import com.heima.model.user.pojos.ApUser;
public interface ApUserService extends IService<ApUser>{
/**
* app端登录
* @param dto
* @return
*/
public ResponseResult login(LoginDto dto);
}
3.1、ServiceImpl¶
思路分析¶
- 登录请求是否包含用户名和密码
- 用户输入了用户名和密码进行登录,用户名和密码校验成功后返回jwt(基于当前用户的id生成)。
- 用户游客登录,生成jwt返回(基于默认值0生成)。
package com.heima.user.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.LoginDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.service.ApUserService;
import com.heima.utils.common.AppJwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import java.util.HashMap;
import java.util.Map;
@Service//注解
@Transactional//事务
@Slf4j//打印日志
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {
/**
* app端登录功能
*
* @param dto
* @return
*/
@Override
public ResponseResult login(LoginDto dto) {
//1.正常登录 用户名和密码都不为空
if (StringUtils.isNotBlank(dto.getPhone()) && StringUtils.isNotBlank(dto.getPassword())) {
//1.1 根据手机号查询用户信息
ApUser dbUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));
if (dbUser == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户信息不存在");
}
//1.2 比对密码
String salt = dbUser.getSalt();//从数据库中获取盐
String password = dto.getPassword();//前端传过来的密码
String pswd = DigestUtils.md5DigestAsHex((password + salt).getBytes());
if (!pswd.equals(dbUser.getPassword())) {//是否和数据库中的密码一样
return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
}
//1.3 返回数据 jwt(token) user
//AppJwtUtil是项目中写的工具类,getToken是AppJwtUtil的静态方法
String token = AppJwtUtil.getToken(dbUser.getId().longValue());
Map<String, Object> map = new HashMap<>();
map.put("token", token);
dbUser.setSalt("");//盐不需要返回给前端
dbUser.setPassword("");//密码不返回给前端
map.put("user", dbUser);
return ResponseResult.okResult(map);
} else {
//2.游客登录
Map<String, Object> map = new HashMap<>();
map.put("token", AppJwtUtil.getToken(0L));
return ResponseResult.okResult(map);
}
}
}
4、控制层controller¶
package com.heima.user.controller.v1;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.user.dtos.LoginDto;
import com.heima.user.service.ApUserService;
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;
@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {
//注入service
@Autowired
private ApUserService apUserService;
@PostMapping("/login_auth")
public ResponseResult login(@RequestBody LoginDto dto) {
return apUserService.login(dto);
}
}