👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者
📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人
专栏:高并发项目
编写用户服务接口
在通用模块编写用户服务接口:
/**
* 商城用户服务
*/
public interface ShoppingUserService {
// 注册时向redis保存手机号+验证码
void saveRegisterCheckCode(String phone,String checkCode);
// 注册时验证手机号
void registerCheckCode(String phone,String checkCode);
// 用户注册
void register(ShoppingUser shoppingUser);
// 用户名密码登录
String loginPassword(String username,String password);
// 登录时向redis保存手机号+验证码
void saveLoginCheckCode(String phone,String checkCode);
// 手机号验证码登录
String loginCheckCode(String phone, String checkCode);
// 获取登录用户名
String getName(String token);
// 获取登录用户
ShoppingUser getLoginUser(String token);
}
创建网站用户服务模块
1、创建名为 shopping_user_service 的SpringBoot工程,添加相关依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MyBatisPlus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.itbaizhan</groupId>
<artifactId>shopping_common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!-- 操作zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
2、设置该工程的父工程为 shopping 。
<parent>
<groupId>com.ittxc</groupId>
<artifactId>shopping</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
3、给 shopping 工程设置子模块
<!-- 子模块 -->
<modules>
<!-- 用户服务 -->
<module>shopping_user_service</module>
</modules>
4、编写配置文件 application.yml
# 端口号
server:
port: 9006
# 日志格式
logging:
pattern:
console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
#配置mybatis-plus
mybatis-plus:
global-config:
db-config:
# 表名前缀
table-prefix: bz_
# 主键生成策略为自增
id-type: auto
configuration:
# 关闭列名自动驼峰命名规则映射
map-underscore-to-camel-case: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql日志
spring:
# 数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///baizhanshopping?serverTimezone=UTC
username: root
password01: 123456
# redis
redis:
host: 192.168.100.131
port: 6379
timeout: 30000
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
dubbo:
application:
name: shopping_user_service # 项目名
registry:
address: zookeeper://192.168.100.131 #注册中心地址
port: 2181 # 注册中心的端口
timeout: 10000 # 注册到zk上超时时间,ms
protocol:
name: dubbo # dubbo使用的协议
port: -1 # dubbo自动分配端口
scan:
base-packages: com.ittxc.shopping_user_service.service # 包扫描
创建网站用户Api模块
1、创建名为 shopping_user_customer_api 的SpringBoot工程,添加相关依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!-- 操作zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>com.itbaizhan</groupId>
<artifactId>shopping_common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、设置该工程的父工程为 shopping 。
<parent>
<groupId>com.ittxc</groupId>
<artifactId>shopping</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
3、给 shopping 工程设置子模块
<!-- 子模块 -->
<modules>
<!-- 用户业务的api -->
<module>shopping_user_customer_api</module>
</modules>
4、编写配置文件 application.yml
# 端口号
server:
port: 8003
# 日志格式
logging:
pattern:
console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
dubbo:
application:
name: shopping_user_customer_api # 项目名
registry:
address: zookeeper://192.168.100.131 #注册中心地址
port: 2181 # 注册中心的端口
timeout: 10000 # 注册到zk上超时时间,ms
protocol:
name: dubbo # dubbo使用的协议
port: -1 # dubbo自动分配端口
5、启动类忽略数据源自动配置
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class ShoppingUserCustomerApiApplication {
public static void main(String[] args)
{
SpringApplication.run(ShoppingUserCustomerApiApplication.class, args);
}
}
用户注册的步骤
在用户注册时,我们要保证用户输入的手机号就是他本人使用的手 机号,方便后期的广告推送、安全认证等。所以在注册前,会向用 户手机发送一个四位随机数验证码,如果用户能获取到该验证码, 证明该手机就是用户本人使用。用户注册的步骤如下:
申请阿里短信服务
1、访问阿里云 https://www.aliyun.com/,完成登录
2、进入短信服务
3、开通短信服务
4、购买短信条数
5、购买完成进入阿里云短信控制台https://dysms.console.aliyun.c om/overview
6、绑定测试手机号
7、点击调用API发送短信,可以看到发送短信的JAVA代码。
8、申请阿里云秘钥,该秘钥在发送短信时会作为参数传入
编写发送短信功能
1、创建名为 shopping_message_service 的SpringBoot工程,添加相关依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.ittxc</groupId>
<artifactId>shopping_common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 阿里短信平台 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.9</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!-- 操作zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、设置该工程的父工程为 shopping 。
<parent>
<groupId>com.ittxc</groupId>
<artifactId>shopping</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
3、给 shopping 工程设置子模块
<!-- 子模块 -->
<modules>
<!-- 短信服务 -->
<module>shopping_message_service</module>
</modules>
4、编写配置文件 application.yml
# 端口号
server:
port: 9007
# 日志格式
logging:
pattern:
console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread]
%cyan(%-50logger{50}):%msg%n'
dubbo:
application:
name: shopping_message_service # 项目名
registry:
address: zookeeper://192.168.100.131 #注册中心地址
port: 2181 # 注册中心的端口
timeout: 10000 # 注册到zk上超时时间,ms
protocol:
name: dubbo # dubbo使用的协议
port: -1 # dubbo自动分配端口
scan:
base-packages: com.ittxc.shopping_message_service.service # 包扫描
message:
accessKeyId: LTAI5tBUnRMTgKmRR92yxrFf
accessKeySecret: RN7umfy3mMA2xlGa8rP0IzwQdTc6Pb
5、启动类忽略数据源自动配置
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class ShoppingMessageServiceApplication {
public static void main(String[] args)
{
SpringApplication.run(ShoppingMessageServiceApplication.class, args);
}
}
6、在通用模块编写发送短信服务接口
/**
* 短信服务
*/
public interface MessageService {
/**
* 发送短信
* @param phoneNumber 手机号
* @param code 验证码
* @return 返回结果
*/
BaseResult sendMessage(String phoneNumber,String code);
}
7、在短信服务模块编写发送短信实现类
@DubboService
public class MessageServiceImpl implements
MessageService {
@Value("${message.accessKeyId}")
private String accessKeyId;
@Value("${message.accessKeySecret}")
private String accessKeySecret;
/**
* 使用AK&SK初始化账号Client
* @param accessKeyId
* @param accessKeySecret
* @return Client
* @throws Exception
*/
@SneakyThrows
private Client createClient(String accessKeyId, String accessKeySecret) {
Config config = new Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret);
// 访问的域名
config.endpoint = "dysmsapi.aliyuncs.com";
return new Client(config);
}
@SneakyThrows
@Override
public BaseResult sendMessage(String phoneNumber,String code) {
Client client = createClient(accessKeyId,accessKeySecret);
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setSignName("阿里云短信测试")
.setTemplateCode("SMS_154950909")
.setPhoneNumbers(phoneNumber)
.setTemplateParam("{\"code\":\""+code+"\"}");
RuntimeOptions runtime = new RuntimeOptions();
// 复制代码运行请自行打印API的返回值
SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest,
runtime);
SendSmsResponseBody body = sendSmsResponse.getBody();
if ("OK".equals(body.getCode())){
return new BaseResult(200,body.getCode(),body.getMessage());
}else{
return new BaseResult(500,body.getCode(),body.getMessage());
}
}
}
8、测试该方法
编写发送注册验证码功能
1、在通用模块编写生成随机数的工具类
public class RandomUtil {
/**
* 生成验证码
* @param digit 位数
* @return
*/
public static String buildCheckCode(int digit){
String str = "0123456789";
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < digit; i++) {
char ch = str.charAt(random.nextInt(str.length()));
sb.append(ch);
}
return sb.toString();
}
}
2、在用户服务模块编写用户服务接口实现类
@DubboService
public class ShoppingUserServiceImpl implements ShoppingUserService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private ShoppingUserMapper shoppingUserMapper;
@Override
public void saveRegisterCheckCode(String phone, String checkCode) {
ValueOperations valueOperations = redisTemplate.opsForValue();
// redis键为手机号,值为验证码,过期时间5分钟
valueOperations.set("registerCode:" + phone, checkCode, 300, TimeUnit.SECONDS);
}
}
3、在用户API模块编写控制器
/**
* 商城用户
*/
@RestController
@RequestMapping("/shoppingUser")
public class ShoppingUserController {
@DubboReference
private ShoppingUserService shoppingUserService;
/**
* 发送注册短信
* @param phone 注册手机号
* @return 操作结果
*/
@GetMapping("/sendMessage")
public BaseResult sendMessage(String phone){
// 1.生成随机四位数
String checkCode = RandomUtil.buildCheckCode(4);
// 2.发送短信
BaseResult result = messageService.sendMessage(phone,checkCode);
// 3.发送成功,将验证码保存到redis中,发送失败,返回发送结果
if (200 == result.getCode()) {
shoppingUserService.saveRegisterCheckCode(phone, checkCode);
return BaseResult.ok();
} else {
return result;
}
}
}
4、测试控制器
编写验证注册验证码功能
1、在用户服务模块编写用户服务接口实现类
@Override
public void registerCheckCode(String phone, String checkCode) {
// 验证验证码
ValueOperations valueOperations = redisTemplate.opsForValue();
Object checkCodeRedis = valueOperations.get("registerCode:" + phone);
if (!checkCode.equals(checkCodeRedis))
{
throw new BusException(CodeEnum.REGISTER_CODE_ERROR);
}
}
2、在用户API模块编写控制器
/**
* 验证用户注册验证码
* @param phone 手机号
* @param checkCode 验证码
* @return 200验证成功,605验证码不正确
*/
@GetMapping("/registerCheckCode")
public BaseResult register(String phone,String checkCode){
shoppingUserService.registerCheckCode(phone,checkCode);
return BaseResult.ok();
}
3、测试控制器
编写用户注册功能
1、在通用模块编写MD5加密工具类,用于给用户密码进行加密和验证
public class Md5Util {
public final static String md5key = "BAIZHAN"; // 秘钥
/**
* 加密
* @param text 明文
* @return 密文
*/
public static String encode(String text){
return DigestUtils.md5Hex(text + md5key);
}
/**
* 验证
*
* @param text 明文
* @param cipher 密文
* @return true/false
*/
public static boolean verify(String text, String cipher){
// 将明文转为密文进行比对
String md5Text = encode(text);
if (md5Text.equalsIgnoreCase(cipher)) {
return true;
}
return false;
}
}
2、在用户服务模块编写用户服务接口实现类
@Override
public void register(ShoppingUser
shoppingUser) {
// 1.验证手机号是否存在
String phone = shoppingUser.getPhone();
QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();
queryWrapper.eq("phone", phone);
List<ShoppingUser> shoppingUsers = shoppingUserMapper.selectList(queryWrapper);
if (shoppingUsers != null && shoppingUsers.size() > 0) {
throw new BusException(CodeEnum.REGISTER_REPEAT_PHONE_ERROR);
}
// 2.验证用户名是否存在
String username = shoppingUser.getUsername();
QueryWrapper<ShoppingUser> queryWrapper1 = new QueryWrapper();
queryWrapper1.eq("username",username);
List<ShoppingUser> shoppingUsers1 = shoppingUserMapper.selectList(queryWrapper1);
if (shoppingUsers1 != null && shoppingUsers1.size() > 0) {
throw new BusException(CodeEnum.REGISTER_REPEAT_NAME_ERROR);
}
// 3.新增用户
shoppingUser.setStatus("Y");
shoppingUser.setPassword(Md5Util.encode(shoppingUser.getPassword()));
shoppingUserMapper.insert(shoppingUser);
}
3、在用户API模块编写控制器
/**
* 用户注册
* @param shoppingUser 用户信息
* @return 注册结果
*/
@PostMapping("/register")
public BaseResult register(@RequestBody ShoppingUser shoppingUser){
shoppingUserService.register(shoppingUser);
return BaseResult.ok();
}
4、测试控制器
编写用户名密码登录功能
1、在用户服务模块编写用户服务接口实现类
@Override
public String loginPassword(String username, String password) {
QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();
queryWrapper.eq("username", username);
ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);
// 验证用户名
if (shoppingUser == null) {
throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);
}
// 验证密码
boolean verify = Md5Util.verify(password,shoppingUser.getPassword());
if (!verify) {
throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);
}
// 返回用户名
return username;
}
2、在用户API模块编写控制器
/**
* 用户名密码登录
* @param shoppingUser 用户对象
* @return 登录结果
*/
@PostMapping("/loginPassword")
public BaseResult loginPassword(@RequestBody ShoppingUser shoppingUser){
shoppingUserService.loginPassword(shoppingUser.getUsername(),shoppingUser.getPassword());
return BaseResult.ok();
}
3、测试控制器
编写手机号验证码登录功能
手机号验证码登录的流程为:用户先输入手机号,向手机号发送随 机验证码,并将验证码保存到redis中。用户收到短信后将验证码输入,如果验证码和redis中的验证码匹配成功,证明登录者就是使用 该手机的用户,登录成功。
向用户发送登录验证码
1、在用户服务模块编写用户服务接口实现类
// 保存登录验证码到redis
@Override
public void saveLoginCheckCode(String phone, String checkCode) {
ValueOperations valueOperations = redisTemplate.opsForValue();
// redis键为手机号,值为验证码,过期时间5分钟
valueOperations.set("loginCode:" + phone, checkCode, 300, TimeUnit.SECONDS);
}
2、在用户API模块编写控制器
/**
* 发送登录短信验证码
*
* @param phone 手机号
* @return 操作结果
*/
@GetMapping("/sendLoginCheckCode")
public BaseResult sendLoginCheckCode(String phone) {
// 1.生成随机四位数
String checkCode = RandomUtil.buildCheckCode(4);
// 2.发送短信
BaseResult result = messageService.sendMessage(phone,checkCode);
// 3.发送成功,将验证码保存到redis中,发送失败,返回发送结果
if (200 == result.getCode()) {
shoppingUserService.saveLoginCheckCode(phone, checkCode);
return BaseResult.ok();
} else {
return result;
}
}
3、测试控制器
验证登录验证码
1、在用户服务模块编写用户服务接口实现类
// 验证登录验证码
@Override
public String loginCheckCode(String phone, String checkCode) {
ValueOperations valueOperations = redisTemplate.opsForValue();
Object checkCodeRedis = valueOperations.get("loginCode:" + phone);
if (!checkCode.equals(checkCodeRedis))
{
throw new BusException(CodeEnum.LOGIN_CODE_ERROR);
}
// 登录成功,查询用户
QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();
queryWrapper.eq("phone", phone);
ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);
// 返回用户名
return shoppingUser.getUsername();
}
2、在用户API模块编写控制器
/**
* 手机号验证码登录
* @param phone 手机号
* @param checkCode 验证码
* @return 登录结果
*/
@PostMapping("/loginCheckCode")
public BaseResult loginCheckCode(String phone, String checkCode){
shoppingUserService.loginCheckCode(phone,checkCode);
return BaseResult.ok();
}
3、测试控制器
单点登录的概念
目前登录成功后我们并没有保存用户信息,也没有在访问接口前验 证用户信息。如果使用传统的session保存用户信息,使用filter验证 用户是否登录。存在一个问题:session保存在服务器中,而我们的 系统存在诸多子系统,这些子系统是分别部署在不同的服务器中,互相无法访问(登录后的session保存在用户模块,搜索模块无法访问用户模块的session,无法验证用户是否登录)。此时我们需要使用单点登录技术解决这一问题。
单点登录
单点登录(Single Sign On)简称为 SSO。即在多个应用系统中, 用户只需要登录一次就可以访问所有相互信任的应用系统。JWT是一种常用的单点登录解决方案。
JWT
JWT是Json Web Token的简称,是一种令牌生成算法。使用JWT能 够保证Token的安全性,且能够进行Token时效性的检验。 使用JWT时,登录成功后将用户信息生成一串令牌字符串。将该字 符串返回给客户端,客户端每次请求时都在请求头携带该令牌字符串。在其他模块验证令牌,通过则证明用户处于登录状态,并拿到 解析后的用户信息,未通过证明用户处于未登录状态。
编写单点登录功能
1、在通用模块引入JWT依赖
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
2、在通用模块编写JWT工具类
public class JWTUtil {
//token过期时间,一天
private static final Long EXPIRE_DATE = 1000*60*60*24L;
// 秘钥
private static final String SECRET = "txc";
// 签发者
private static final String ISSUER = "TXC";
/**
* 签名生成
* @param shoppingUser
* @return
*/
public static String sign(ShoppingUser shoppingUser){
String token = JWT.create()
.withIssuer(ISSUER) // 签发者
.withIssuedAt(new Date())// 签发时间
.withExpiresAt(new Date(new Date().getTime() + EXPIRE_DATE))// 过期时间
.withSubject(shoppingUser.getUsername())// 保存用户名
.sign(Algorithm.HMAC256(SECRET)); // 秘钥
return token;
}
/**
* 签名解析
* @param token 签名字符串
* @return 解析得出的用户名
*/
public static String verify(String token){
try {
String username = JWT
.require(Algorithm.HMAC256(SECRET))
.withIssuer(ISSUER)
.build()
.verify(token)
.getSubject();
return username;
} catch (Exception e){
throw new BusException(CodeEnum.VERIFY_TOKEN_ERROR);
}
}
}
3、登录后生成令牌
@Override
public String loginPassword(String
username, String password) {
// 1.验证用户名
QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();
queryWrapper.eq("username",username);
ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);
if (shoppingUser == null){
throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);
}
// 2.验证密码
boolean verify = Md5Util.verify(password, shoppingUser.getPassword());
if (!verify){
throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);
}
// 3.生成JWT令牌,返回令牌
String sign = JWTUtil.sign(shoppingUser);
return sign;
}
@Override
public String loginCheckCode(String phone,String checkCode) {
ValueOperations valueOperations = redisTemplate.opsForValue();
Object checkCodeRedis = valueOperations.get("loginCode:" + phone);
if (!checkCode.equals(checkCodeRedis))
{
throw new BusException(CodeEnum.LOGIN_CODE_ERROR);
}
// 登录成功,查找用户,返回用户名
QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();
queryWrapper.eq("phone",phone);
ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);
// 生成JWT令牌,返回令牌
String sign = JWTUtil.sign(shoppingUser);
return sign;
}
4、将令牌返回给客户端
/**
* 用户名密码登录
* @param shoppingUser 用户对象
* @return 登录结果
*/
@PostMapping("/loginPassword")
public BaseResult loginPassword(@RequestBody ShoppingUser shoppingUser){
String sign = shoppingUserService.loginPassword(shoppingUser.getUsername(),shoppingUser.getPassword());
return BaseResult.ok(sign);
}
/**
* 手机号验证码登录
* @param phone 手机号
* @param checkCode 验证码
* @return 登录结果
*/
@PostMapping("/loginCheckCode")
public BaseResult loginCheckCode(Stringphone,String checkCode){
String sign = shoppingUserService.loginCheckCode(phone,checkCode);
return BaseResult.ok(sign);
}
编写拦截器验证令牌
在通用模块编写JWT拦截器
// 拦截器,验证令牌
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Objecthandler) throws Exception {
// 获取请求头中的token
String token = request.getHeader("token");
// 验证token
JWTUtil.verify(token);
return true;
}
}
注:请求时要在请求头添加token=令牌数据
配置拦截的接口
在不同API模块都要配置拦截的接口
1、配置用户API模块拦截的接口
// 拦截器配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/**") //拦截的接口
.excludePathPatterns(
"/user/shoppingUser/sendMessage",
"/user/shoppingUser/registerCheckCode",
"/user/shoppingUser/register",
"/user/shoppingUser/loginPassword",
"/user/shoppingUser/sendLoginCheckCode",
"/user/shoppingUser/loginCheckCode"
); //放行的接口
}
}
2、配置搜索API模块拦截的接口
// 拦截器配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/**") //拦截的接口
.excludePathPatterns("/user/goodsSearch/autoSuggest"); //放行的接口
}
}
3、广告用户API模块不拦截
编写获取用户名功能
1、在用户服务模块编写用户服务接口实现类
@Override
public String getName(String token) {
String name = JWTUtil.verify(token);
return name;
}
@Override
public ShoppingUser getLoginUser(String token) {
String username = JWTUtil.verify(token);
QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();
queryWrapper.eq("username", username);
ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);
return shoppingUser;
}
2、在用户API模块编写控制器
/**
* 获取登录的用户名
* @param token 令牌
* @return 用户名
*/
@GetMapping("/getName")
public BaseResult<String> getName(@RequestHeader("token") String token){
String name = shoppingUserService.getName(token);
return BaseResult.ok(name);
}
3、使用Postman测试控制器
编写退出登录功能
后端无需编写退出登录功能,前端删除令牌即可退出登录。