对于本文

其实用户登录拦挡的这块不想这么早写,加个登录前面好多货色就要思考登录状态了,我其实想把这个系列写成非必要关系,解耦性比拟强的系列。然而,写完redis,总是感觉登录是对它最简略的实际,那就加上吧,反正前面很多文章也会用到,但大多文章我仍会不思考登录状态。

这里只是讲明确登录机制,如何实现。理论应用中会思考很多别的,例如用户权限,登录机制限度等等~这里就先不做过多的叙述。

这里只讲技术和实现,不讲任何业务场景哈,牵扯到场景的问题就会简单N倍,而且通用性往往不尽人意~

本文依赖于redis和mybatis plus,这些都是最根底的模块,所以都放在最后面写了,大家能够线过一下相干的文章。

[SpringBoot集成Redis]()

[SpringBoot集成Mybatis Plus]()

本文是基于jwt+redis来实现。接下来咱们一起看看吧

什么是JWT

什么是JWT,JWT(全称:Json Web Token)是一个凋谢规范(RFC 7519),它定义了一种紧凑的、自蕴含的形式,用于作为JSON对象在各方之间平安地传输信息。 该信息能够被验证和信赖,因为它是数字签名的。

下面说法比拟文绉绉,简略点说就是一种认证机制,让后盾晓得该申请是来自于受信的客户端。

JWT的长处

  • json格局的通用性,所以JWT能够跨语言反对,比方Java、JavaScript、PHP、Node等等。
  • 能够利用Payload存储一些非敏感的信息。
  • 便于传输,JWT构造简略,字节占用小。
  • 不须要在服务端保留会话信息,易于利用的扩大。

JWT的毛病

  • 安全性没法保障,所以jwt里不能存储敏感数据。因为jwt的payload并没有加密,只是用Base64编码而已。
  • 无奈中途废除。因为一旦签发了一个jwt,在到期之前始终都是无效的,如果用户信息产生更新了,只能等旧的jwt过期后从新签发新的jwt。
  • 续签问题。当签发的jwt保留在客户端,客户端始终在操作页面,按情理应该始终为客户端续长无效工夫,否则当jwt有效期到了就会导致用户须要从新登录。

弥补JWT的毛病

  • 针对JWT的毛病,咱们在应用的过程中,只贮存罕用的无敏感数据,比方用户ID,用户角色等。
  • 中途废除和续签问题,通过和redis配合应用,将token返回时,同步保留redis,通过管制token在redis的有效期来进行管制。
  • 还能够通过统计redis无效数据,对在线用户进行统计或强制下线等操作。

用户登录流程

以用户登录性能为例,程序流程如下:

用户登录

token认证拜访

注:零碎中采纳JWT对用户登录受权验证。

基于Token的身份验证流程

应用基于Token的身份验证,在服务端不须要存储用户的登录记录。大略的流程是这样的:

1、客户端应用用户名或明码申请登录;

2、服务端收到申请,去验证用户名与明码;

3、验证胜利后,服务端会应用JWT签发一个Token,保留到Redis中,同时再把这个Token发送给客户端;

4、客户端收到Token当前能够把它存储起来,比方放在Cookie里或者Local Storage里;

5、客户端每次向服务端申请资源的时候须要在申请Header外面带着服务端签发的Token;

6、服务端收到申请,而后去验证客户端申请外面带着的Token,如果验证胜利,就向客户端返回申请的数据。验证失败,返回失败起因。

性能实现

主动生成的User.javaUserMapper.javaUserMapper.xml...就不贴代码了,没有业务代码,且占的篇幅过大。在[SpringBoot集成Mybatis Plus]()文章中创立过就能够疏忽了哈~

代码生成见[SpringBoot集成Mybatis Plus]()一文。

波及到的表sql

在[SpringBoot集成Mybatis Plus]()文章中创立过的就能够疏忽了

CREATE TABLE `usc_user` (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',  `account` varchar(30) DEFAULT NULL COMMENT '用户账号',  `user_name` varchar(30) DEFAULT NULL COMMENT '用户姓名',  `nick_name` varchar(30) DEFAULT NULL COMMENT '用户昵称',  `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00零碎用户,01小程序用户)',  `email` varchar(50) DEFAULT '' COMMENT '用户邮箱',  `phone` varchar(11) DEFAULT '' COMMENT '手机号码',  `sex` char(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',  `avatar` varchar(100) DEFAULT '' COMMENT '头像地址',  `salt` varchar(32) DEFAULT NULL COMMENT '用户加密盐值',  `password` varchar(100) DEFAULT '' COMMENT '明码',  `status` char(1) DEFAULT '0' COMMENT '帐号状态(0失常 1停用)',  `create_id` bigint(20) DEFAULT NULL COMMENT '创建人id',  `create_name` varchar(64) DEFAULT '' COMMENT '创建者',  `create_time` datetime DEFAULT NULL COMMENT '创立工夫',  `update_id` bigint(20) DEFAULT NULL COMMENT '更新人id',  `update_name` varchar(64) DEFAULT '' COMMENT '更新者',  `update_time` datetime DEFAULT NULL COMMENT '更新工夫',  `delete_flag` tinyint(1) DEFAULT '0' COMMENT '删除标记',  `remark` varchar(500) DEFAULT NULL COMMENT '备注',  PRIMARY KEY (`id`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户核心-用户信息表';

引入依赖

首先咱们在pom文件中引入依赖

<!-- 引入JWT相干 --><dependency>    <groupId>com.auth0</groupId>    <artifactId>java-jwt</artifactId>    <version>3.18.3</version></dependency>

通用类

先把咱们的通用类创立一下,一些常量,咱们对立放在一个配置中,不便日后保护。

  • 在config.bean创立通用类GlobalConfig.java
package com.maple.demo.config.bean;/** * @author 笑小枫 * @date 2022/7/20 */public class GlobalConfig {    private GlobalConfig() {    }    /**     * 用户贮存在redis中的过期工夫     */    public static final long EXPIRE_TIME = 60 * 60 * 12L;    /**     * 生成token的私钥     */    public static final String SECRET = "maple123";        /**     * 前端传递token的header名称     */    public static final String TOKEN_NAME = "Authorization";    /**     * 用户登录token保留在redis的key值     *     * @param account 用户登录帐号     * @return token保留在redis的key     */    public static String getRedisUserKey(String account) {        return "MAPLE_ADMIN:" + account;    }}
  • config.bean创立TokenBean.java保留的jwt的信息
package com.maple.demo.config.bean;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.RequiredArgsConstructor;/** * @author 笑小枫 * @date 2022/7/20 */@Data@Builder@RequiredArgsConstructor@AllArgsConstructorpublic class TokenBean {    /**     * 用户ID     */    private Long userId;    /**     * 用户账号     */    private String account;    /**     * 用户类型     */    private String userType;}

JWT工具类

在咱们的util包下创立JwtUtil.java工具类

package com.maple.demo.util;import com.auth0.jwt.JWT;import com.auth0.jwt.JWTVerifier;import com.auth0.jwt.algorithms.Algorithm;import com.auth0.jwt.exceptions.JWTDecodeException;import com.auth0.jwt.interfaces.DecodedJWT;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.bean.GlobalConfig;import com.maple.demo.config.bean.TokenBean;import com.maple.demo.config.exception.MapleCheckException;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.util.Objects;/** * Jwt罕用操作 * * @author 笑小枫 * @date 2022/7/20 */public class JwtUtil {    private static final String ACCOUNT = "account";    private static final String USER_ID = "userId";    private static final String USER_TYPE = "userType";    /**     * 校验token是否正确     *     * @param token 密钥     * @return 是否正确     */    public static boolean verify(String token, String account) {        try {            Algorithm algorithm = Algorithm.HMAC256(GlobalConfig.SECRET);            JWTVerifier verifier = JWT.require(algorithm).withClaim(ACCOUNT, account).build();            verifier.verify(token);            return true;        } catch (Exception exception) {            return false;        }    }    /**     * 取得token中的信息无需secret解密也能取得     *     * @return token中蕴含的用户登录帐号     */    public static String getAccount() {        try {            DecodedJWT jwt = getJwt();            if (jwt == null) {                return null;            }            return jwt.getClaim(ACCOUNT).asString();        } catch (JWTDecodeException e) {            return null;        }    }    /**     * 取得token中的信息无需secret解密也能取得     *     * @return token中蕴含的用户登录帐号     */    public static String getAccount(String token) {        try {            DecodedJWT jwt = JWT.decode(token);            return jwt.getClaim(ACCOUNT).asString();        } catch (JWTDecodeException e) {            return null;        }    }    public static Long getUserId() {        try {            DecodedJWT jwt = getJwt();            if (jwt == null) {                return null;            }            return jwt.getClaim(USER_ID).asLong();        } catch (JWTDecodeException e) {            return null;        }    }    /**     * 取得token中的信息无需secret解密也能取得     *     * @return token中蕴含的用户ID     */    public static Long getUserId(String token) {        try {            DecodedJWT jwt = JWT.decode(token);            return jwt.getClaim(USER_ID).asLong();        } catch (JWTDecodeException e) {            return null;        }    }    public static TokenBean getTokenMsg() {        TokenBean tokenBean = new TokenBean();        try {            DecodedJWT jwt = getJwt();            if (jwt == null) {                return tokenBean;            }            tokenBean.setUserId(jwt.getClaim(USER_ID).asLong());            tokenBean.setAccount(jwt.getClaim(ACCOUNT).asString());            return tokenBean;        } catch (JWTDecodeException e) {            return tokenBean;        }    }    private static DecodedJWT getJwt() {        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();        if (Objects.isNull(servletRequestAttributes)) {            throw new MapleCheckException(ErrorCode.PARAM_ERROR);        }        HttpServletRequest request = servletRequestAttributes.getRequest();        String authorization = request.getHeader(GlobalConfig.TOKEN_NAME);        if (authorization == null) {            return null;        }        return JWT.decode(authorization);    }    /**     * 校验token是否无效     *     * @param token token信息     * @return 返回后果     */    public static boolean verifyToken(String token) {        try {            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(GlobalConfig.SECRET)).build();            DecodedJWT jwt = verifier.verify(token);            jwt.getClaims();            return true;        } catch (Exception e) {            e.printStackTrace();            return false;        }    }    /**     * 创立token     *     * @param tokenBean token保留的信息     * @return token     */    public static String createToken(TokenBean tokenBean) {        Algorithm algorithm = Algorithm.HMAC256(GlobalConfig.SECRET);        return JWT.create()                .withClaim(USER_ID, tokenBean.getUserId())                .withClaim(ACCOUNT, tokenBean.getAccount())                .withClaim(USER_TYPE, tokenBean.getUserType())                .sign(algorithm);    }}

Filter登录拦截器

牵扯到了三个异样code,咱们能够在ErrorCode.java外面补充一下,如果没有引入自定义异样,能够手动throw new RuntimeException("笑小枫的异样信息")替换一下就行了。

NO_TOKEN("1001", "用户未登录"),TOKEN_EXPIRE("1002", "登陆超时,请从新登录"),TOKEN_EXCHANGE("1003", "账号在其余中央登录,账号被踢出"),USER_LOGIN_ERROR("2001", "用户名或明码谬误"),USER_STATUS_ERROR("2002", "用户已被停用,请分割管理员"),

首先在MapleDemoApplication.java启动项上增加注解@ServletComponentScan

SpringBootApplication 上应用@ServletComponentScan 注解后

Servlet能够间接通过@WebServlet注解主动注册

Filter能够间接通过@WebFilter注解主动注册

Listener能够间接通过@WebListener 注解主动注册

创立一个寄存拦截器的包filter,而后在包内创立咱们的拦截器JwtFilter,代码如下:

package com.maple.demo.filter;import com.alibaba.fastjson.JSON;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.bean.GlobalConfig;import com.maple.demo.util.JwtUtil;import com.maple.demo.util.RedisUtil;import com.maple.demo.util.ResultJson;import lombok.AllArgsConstructor;import org.springframework.beans.factory.BeanFactory;import org.springframework.core.annotation.Order;import org.springframework.http.HttpMethod;import org.springframework.util.StringUtils;import org.springframework.web.context.support.WebApplicationContextUtils;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Arrays;import java.util.List;import java.util.regex.Pattern;/** * 判断用户登录token * * @author 笑小枫 * @date 2022/07/20 */@WebFilter(filterName = "jwtFilter", urlPatterns = {"/*"})@AllArgsConstructor@Order(1)public class JwtFilter implements Filter {    private final List<String> excludedUrlList;    @Override    public void init(FilterConfig filterConfig) {        excludedUrlList.addAll(Arrays.asList(                "/sso/login",                "/sso/logout",                "/example/*",                "/webjars/**",                "/swagger/**",                "/v2/api-docs",                "/doc.html",                "/swagger-ui.html",                "/swagger-resources/**",                "/swagger-resources"        ));    }    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        String url = ((HttpServletRequest) request).getRequestURI();        boolean isMatch = false;        for (String excludedUrl : excludedUrlList) {            if (Pattern.matches(excludedUrl.replace("*", ".*"), url)) {                isMatch = true;                break;            }        }        if (isMatch) {            chain.doFilter(request, response);        } else {            HttpServletRequest httpServletRequest = (HttpServletRequest) request;            HttpServletResponse httpServletResponse = (HttpServletResponse) response;            //解决跨域问题,跨域的申请首先会发一个options类型的申请            if (httpServletRequest.getMethod().equals(HttpMethod.OPTIONS.name())) {                chain.doFilter(request, response);            }            BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());            RedisUtil redisService = (RedisUtil) factory.getBean("redisUtil");            String account;            String authorization = httpServletRequest.getHeader(GlobalConfig.TOKEN_NAME);            // 判断token是否存在,不存在代表未登录            if (StringUtils.isEmpty(authorization)) {                writeRsp(httpServletResponse, ErrorCode.NO_TOKEN);                return;            } else {                account = JwtUtil.getAccount(authorization);                String token = (String) redisService.get(GlobalConfig.getRedisUserKey(account));                // 判断token是否存在,不存在代表登陆超时                if (StringUtils.isEmpty(token)) {                    writeRsp(httpServletResponse, ErrorCode.TOKEN_EXPIRE);                    return;                } else {                    // 判断token是否相等,不相等代表在其余中央登录                    if (!token.equalsIgnoreCase(authorization)) {                        writeRsp(httpServletResponse, ErrorCode.TOKEN_EXCHANGE);                        return;                    }                }            }            // 保留redis,每次调用胜利都刷新过期工夫            redisService.set(GlobalConfig.getRedisUserKey(account), authorization, GlobalConfig.EXPIRE_TIME);            chain.doFilter(httpServletRequest, httpServletResponse);        }    }    @Override    public void destroy() {        Filter.super.destroy();    }    private void writeRsp(HttpServletResponse response, ErrorCode errorCode) {        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);        response.setHeader("content-type", "application/json;charset=UTF-8");        try {            response.getWriter().println(JSON.toJSON(new ResultJson(errorCode.getCode(), errorCode.getMsg())));        } catch (IOException e) {            e.printStackTrace();        }    }}

明码加密与验证

首先再自定义一个异样吧,创立一个通用点的MapleCommonException.java,后续都偷懒对立抛这个异样了

代码如下:

package com.maple.demo.config.exception;import com.maple.demo.config.bean.ErrorCode;/** * 通用异样,偷懒就抛出此异样吧 * * @author 笑小枫 * @date 2022/07/20 */public class MapleCommonException extends MapleBaseException {    public MapleCommonException(String code, String errorMsg) {        super(code, errorMsg);    }    public MapleCommonException(ErrorCode code) {        super(code);    }    public MapleCommonException(ErrorCode code, String errorMsg) {        super(code, errorMsg);    }}

明码加密就简略的应用md5加盐值吧,代码如下

package com.maple.demo.util;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.exception.MapleCommonException;import lombok.extern.slf4j.Slf4j;import org.springframework.util.DigestUtils;import org.springframework.util.StringUtils;/** * MD5撒盐加密 及MD5加密 * * @author 笑小枫 * @date 2022/7/20 */@Slf4jpublic class Md5Util {    private Md5Util() {    }    /**     * 明码加密解决     *     * @param password 明码明文     * @param salt     盐     * @return 加密后密文     */    public static String encrypt(String password, String salt) {        if (StringUtils.isEmpty(password) || StringUtils.isEmpty(salt)) {            log.error("明码加密失败起因: password and salt cannot be empty");            throw new MapleCommonException(ErrorCode.PARAM_ERROR);        }        return DigestUtils.md5DigestAsHex((salt + password).getBytes());    }    /**     * 校验明码     *     * @param target 待校验明码     * @param source 原明码     * @param salt   加密原明码的盐     */    public static boolean verifyPassword(String target, String source, String salt) {        if (StringUtils.isEmpty(target) || StringUtils.isEmpty(source) || StringUtils.isEmpty(salt)) {            log.info("校验明码失败,起因 target ={}, source ={}, salt ={}", target, source, salt);            return false;        }        String targetEncryptPwd = encrypt(target, salt);        return targetEncryptPwd.equals(source);    }    public static void main(String[] args) {        log.info(encrypt("admin111", "123456"));    }}

通过main办法生成一个加密后的值吧,而后把盐值和明码都扔到数据库外面,前面咱们就依据账号(account)和明码(password)进行登录。

留神:创立用户的时候先随机生成一个盐(salt),后续依据盐值再去生成明码。

用户登录接口

model和param

创立一个vo包吧,后续的model和query对象对立放在这里了~

在vo包下创立一个query包,而后创立登录申请对象LoginQuery.java

package com.maple.demo.vo.query;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;/** * @author 笑小枫 * @date 2022/7/20 */@Data@ApiModel(value = "用户登录申请对象", description = "用户核心-用户登录申请对象")public class LoginQuery {    @ApiModelProperty(value = "登录账号")    private String account;    @ApiModelProperty(value = "登录明码")    private String password;}

在vo包下创立一个model包,而后创立返回的用户信息对象UserModel.java

package com.maple.demo.vo.model;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.RequiredArgsConstructor;/** * 用户核心-用户信息 * * @author 笑小枫 * @date 2022/7/20 */@Data@Builder@RequiredArgsConstructor@AllArgsConstructor@ApiModel(value = "用户视图对象", description = "用户核心-用户信息")public class UserModel {    @ApiModelProperty(value = "用户ID")    private Long id;    @ApiModelProperty(value = "用户账号")    private String account;    @ApiModelProperty(value = "用户姓名")    private String userName;    @ApiModelProperty(value = "用户昵称")    private String nickName;    @ApiModelProperty(value = "用户类型")    private String userType;    @ApiModelProperty(value = "用户邮箱")    private String email;    @ApiModelProperty(value = "手机号码")    private String phone;    @ApiModelProperty(value = "用户性别")    private String sex;    @ApiModelProperty(value = "头像地址")    private String avatar;    @ApiModelProperty(value = "帐号状态")    private String status;    @ApiModelProperty(value = "备注")    private String remark;    @ApiModelProperty(value = "用户验证Token")    private String token;}

controller

package com.maple.demo.controller;import com.maple.demo.service.IUserService;import com.maple.demo.vo.model.UserModel;import com.maple.demo.vo.query.LoginQuery;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import lombok.AllArgsConstructor;import org.springframework.web.bind.annotation.*;/** * 零碎登录 * * @author 笑小枫 * @date 2022/7/20 */@Api(tags = "管理系统-零碎登录操作")@RestController@AllArgsConstructor@RequestMapping(value = "/sso")public class LoginController {    private final IUserService userService;    @ApiOperation(value = "用户登录")    @PostMapping("/login")    public UserModel login(@RequestBody LoginQuery req) {        return userService.login(req);    }    @ApiOperation(value = "用户退出登录")    @GetMapping("/logout")    public void logout() {        userService.logout();    }}

service

package com.maple.demo.service;import com.baomidou.mybatisplus.extension.service.IService;import com.maple.demo.entity.User;import com.maple.demo.vo.model.UserModel;import com.maple.demo.vo.query.LoginQuery;/** * <p> * 用户核心-用户信息表 服务类 * </p> * * @author 笑小枫 * @since 2022-07-11 */public interface IUserService extends IService<User> {    /**     * 用户登录     *     * @param req 用户信息     * @return 用户登录信息     */    UserModel login(LoginQuery req);    /**     * 退出零碎,革除用户token     */    void logout();}

serviceImpl

package com.maple.demo.service.impl;import com.baomidou.mybatisplus.core.toolkit.Wrappers;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.bean.GlobalConfig;import com.maple.demo.config.bean.TokenBean;import com.maple.demo.config.exception.MapleCheckException;import com.maple.demo.entity.User;import com.maple.demo.mapper.UserMapper;import com.maple.demo.service.IUserService;import com.maple.demo.util.JwtUtil;import com.maple.demo.util.Md5Util;import com.maple.demo.util.RedisUtil;import com.maple.demo.vo.model.UserModel;import com.maple.demo.vo.query.LoginQuery;import lombok.AllArgsConstructor;import org.springframework.beans.BeanUtils;import org.springframework.stereotype.Service;import java.util.Objects;/** * <p> * 用户核心-用户信息表 服务实现类 * </p> * * @author Maple * @since 2022-07-11 */@Service@AllArgsConstructorpublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {    private final UserMapper userMapper;    private final RedisUtil redisUtil;    @Override    public UserModel login(LoginQuery req) {        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)                .eq(User::getAccount, req.getAccount())                .last("LIMIT 1"));        if (Objects.isNull(user)) {            throw new MapleCheckException(ErrorCode.USER_LOGIN_ERROR);        }        if ("1".equals(user.getStatus())) {            throw new MapleCheckException(ErrorCode.USER_STATUS_ERROR);        }        if (!Md5Util.verifyPassword(req.getPassword(), user.getPassword(), user.getSalt())) {            throw new MapleCheckException(ErrorCode.USER_LOGIN_ERROR);        }        TokenBean tokenBean = TokenBean.builder()                .userId(user.getId())                .userType(user.getUserType())                .account(user.getUserName())                .build();        UserModel userModel = new UserModel();        BeanUtils.copyProperties(user, userModel);        String token;        try {            token = JwtUtil.createToken(tokenBean);        } catch (Exception e) {            log.error(e.getMessage());            throw new MapleCheckException(ErrorCode.COMMON_ERROR);        }        userModel.setToken(token);        redisUtil.set(GlobalConfig.getRedisUserKey(user.getAccount()), token);        return userModel;    }    @Override    public void logout() {        redisUtil.remove(GlobalConfig.getRedisUserKey(JwtUtil.getAccount()));    }}

应用JWT的用户信息

间接应用JwtUtil.class工具类里的办法,即可拿到对应的数据

JwtUtil.getUserId();JwtUtil.getAccount();

功能测试

测试之前须要在数据中增加一条数据

INSERT INTO `maple`.`usc_user`( `account`, `user_name`, `nick_name`, `user_type`, `email`, `phone`, `sex`, `avatar`, `salt`, `password`, `status`, `create_id`, `create_name`, `create_time`, `update_id`, `update_name`, `update_time`, `delete_flag`, `remark`) VALUES ('admin', 'admin', '笑小枫', '00', '1150640979@qq.com', '18300000001', '0', '', '123456', 'e9c764f9b51772f00af80a54d38a692e', '0', 1, '笑小枫', '2022-07-11 13:48:44', 1, '笑小枫', '2022-07-11 13:48:44', 0, '管理员');

间接在LoginController.java外面增加getUserId办法进行测试,具体代码如下:

package com.maple.demo.controller;import com.maple.demo.service.IUserService;import com.maple.demo.util.JwtUtil;import com.maple.demo.vo.model.UserModel;import com.maple.demo.vo.query.LoginQuery;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import lombok.AllArgsConstructor;import org.springframework.web.bind.annotation.*;/** * 零碎登录 * * @author 笑小枫 * @date 2022/7/20 */@Api(tags = "管理系统-零碎登录操作")@RestController@AllArgsConstructor@RequestMapping(value = "/sso")public class LoginController {    private final IUserService userService;    @ApiOperation(value = "用户登录")    @PostMapping("/login")    public UserModel login(@RequestBody LoginQuery req) {        return userService.login(req);    }    @ApiOperation(value = "用户退出登录")    @GetMapping("/logout")    public void logout() {        userService.logout();    }    @ApiOperation(value = "获取登录用户信息")    @GetMapping("/getUserId")    public String getUserId() {        return "以后登录用户的ID为" + JwtUtil.getUserId();    }}

在未登录状态申请接口,返回信息如下:

调用登录接口,进行用户登录

登录后,拿到token,在申请头设置Authorization参数

增加完之后,记得要把tab页敞开,再关上,而后header参数才会失效,在申请头部能够看到

再次调用,返回信息如下:

能够看到,到此咱们的登录拦挡性能就曾经齐全实现了。

小结

好啦,本文就到这里了,咱们简略的总结一下,次要介绍了以下内容

  • 介绍了什么是JWT
  • 用户登录拦挡
  • 用户登录实现

对于笑小枫

本章到这里完结了,喜爱的敌人关注一下我呦,大伙的反对,就是我保持写下去的能源。
老规矩,懂了就点赞珍藏;不懂就问,日常在线,我会就会回复哈~
微信公众号:笑小枫
笑小枫集体博客:https://www.xiaoxiaofeng.com
CSDN:https://zhangfz.blog.csdn.net
本文源码:https://github.com/hack-feng/maple-demo