实战篇03:登录接口

实战篇03:登录接口

一、登录接口信息

1.1 基本信息

请求路径:/user/login

请求方式:POST

接口描述:该接口用于登录

1.2 请求参数

请求参数格式:x-www-form-urlencoded

请求参数说明:

参数名称说明类型是否必须备注
username用户名string5~16位非空字符
password密码string5~16位非空字符

请求数据样例:

username=zhangsan&password=123456

1.3 响应数据

响应数据类型:application/json

响应参数说明:

名称类型是否必须默认值备注其他信息
codenumber必须响应码, 0-成功,1-失败
messagestring非必须提示信息
datastring必须返回的数据,jwt令牌

响应数据样例:

{
    "code": 0,
    "message": "操作成功",
    "data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOnsiaWQiOjUsInVzZXJuYW1lIjoid2FuZ2JhIn0sImV4cCI6MTY5MzcxNTk3OH0.pE_RATcoF7Nm9KEp9eC3CzcBbKWAFOL0IsuMNjnZ95M"
}

1.4 备注说明

用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,浏览器都需要在请求头header中携带到服务端,请求头的名称为 Authorization,值为 登录时下发的JWT令牌。

如果检测到用户未登录,则http响应状态码为401

二、业务流程

  1. Controller进行Post登录校验
    1. 根据用户名查询User
    2. 判断用户名是否正确
    3. 判断密码是否正确
  2. Service曾和Mapper曾提供对应的方法供Controller使用(可以复用注册,已完成)

在这里插入图片描述

三、编写登录Controller

  1. 在UserController类中新增login方法,实现登录功能
package com.example.bigevent.controller;

import com.example.bigevent.pojo.Result;
import com.example.bigevent.pojo.User;
import com.example.bigevent.service.UserService;
import jakarta.validation.constraints.Pattern;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
@Validated
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/register")
    public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password){
        // 查询用户名是否被占用
        User u = userService.findByUserName(username);
        if (u==null){
            // 没有占用,进行注册
            userService.register(username,password);
            return Result.success();
        }else {
            return Result.error("用户名已被占用");
        }
    }

    @PostMapping("/login")
    public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password){
        // 根据用户名查询用户
        User loginUser = userService.findByUserName(username);
        // 判断用户是否存在
        if(loginUser==null){
            return Result.error("用户名错误");
        }
        // 判断密码是否正确
        String md5String = DigestUtils.md5Hex(password);
        if(loginUser.getPassword().equals(md5String)){
            // 登陆成功
            return Result.success("jwt token 令牌");
        }
        return Result.error("密码错误");
    }
}

四、功能测试

  1. 使用postman访问/user/login进行功能测试

在这里插入图片描述

五、登录认证

  1. 新建ArticleController类,用于测试访问该接口前必须登录
package com.example.bigevent.controller;

import com.example.bigevent.pojo.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/article")
public class ArticleController {
    @GetMapping("/list")
    public Result list(){
        return Result.success("所有文章数据...");
    }
}
  1. 引入JWT依赖
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>4.4.0</version>
</dependency>
  1. 在测试中生成JWT令牌

在这里插入图片描述

package com.example.bigevent;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@SpringBootTest
class BigEventApplicationTests {

	@Test
	void contextLoads() {
	}

	@Test
	public void testJWT(){
		Map<String, Object>claims = new HashMap<>();
		claims.put("id",1);
		claims.put("username","xxx");
		String token = JWT.create().withClaim("user", claims)
				.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
				.sign(Algorithm.HMAC256("qwe"));
		System.out.println(token);
	}

}
  1. 在测试中验证JWT令牌
@Test
public void testJWTParse(){
    String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6Inh4eCJ9LCJleHAiOjE3MTIwODQ0MzF9.KSd3aq2frdPjUwnyU-uFoC_MG6gB5wId7OTmPdWG9hA";
    JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("qwe")).build();
    // 进行验证
    DecodedJWT decodedJWT = jwtVerifier.verify(token);
    Map<String, Claim> claims = decodedJWT.getClaims();
    System.out.println(claims.get("user"));
}
  1. 生成JWT工具类:JwtUtil

在这里插入图片描述

package com.example.bigevent.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

import java.util.Date;
import java.util.Map;

public class JwtUtil {

    private static final String KEY = "itheima";

    //接收业务数据,生成token并返回
    public static String genToken(Map<String, Object> claims) {
        return JWT.create()
                .withClaim("claims", claims)
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
                .sign(Algorithm.HMAC256(KEY));
    }

    //接收token,验证token,并返回业务数据
    public static Map<String, Object> parseToken(String token) {
        return JWT.require(Algorithm.HMAC256(KEY))
                .build()
                .verify(token)
                .getClaim("claims")
                .asMap();
    }

}
  1. 在UserController中登录功能生成JWT token
@PostMapping("/login")
public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password){
    // 根据用户名查询用户
    User loginUser = userService.findByUserName(username);
    // 判断用户是否存在
    if(loginUser==null){
        return Result.error("用户名错误");
    }
    // 判断密码是否正确
    String md5String = DigestUtils.md5Hex(password);
    if(loginUser.getPassword().equals(md5String)){
        // 登陆成功
        Map<String,Object> claims = new HashMap<>();
        claims.put("id",loginUser.getId());
        claims.put("username",loginUser.getUsername());
        String token = JwtUtil.genToken(claims);
        return Result.success(token);
    }
    return Result.error("密码错误");
}
}
  1. 根据接口文档1.4备注说明,在ArticleController类中添加验证JWT token行为,实现访问功能函数前需要登陆
    1. 在请求头中获取对应数据,应该使用注解:@RequestHeader(name = “Authorization”)
    2. 使用HttpServletResponse response对象设置返回状态码

六、认证测试

  1. 登录账户,获取JWT字符串
  2. 在postman中使用get请求,header中添加token字符串

在这里插入图片描述

七、使用拦截器实现登录认证

  1. 创建拦截器包:interceptors,创建拦截器类:LoginInterceptor
package com.example.bigevent.interceptors;

import com.example.bigevent.pojo.Result;
import com.example.bigevent.utils.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 令牌验证
        String token = request.getHeader("Authorization");
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            // 拦截器放行
            return true;
        }catch (Exception e){
            response.setStatus(401);
            return false;
        }
    }
}
  1. 注册拦截器,创建包:config,创建类:WebConfig
package com.example.bigevent.config;

import com.example.bigevent.interceptors.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 放行登录和注册接口
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
    }
}
  1. 删除ArticleController中的验证代码
package com.example.bigevent.controller;

import com.example.bigevent.pojo.Result;
import com.example.bigevent.utils.JwtUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/article")
public class ArticleController {
    @GetMapping("/list")
    public Result list(/*@RequestHeader(name = "Authorization") String token, HttpServletResponse response*/){
        return Result.success("所有文章数据...");
//        // 验证token
//        try {
//            Map<String, Object> claims = JwtUtil.parseToken(token);
//            return Result.success("所有文章数据...");
//        }catch (Exception e){
//            response.setStatus(401);
//            return Result.error("未登录");
//        }
    }
}
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值