Uso de Session y JWT en proyectos

Uso de Session y JWT en proyectos

Esta publicación de blog presentará y mostrará el código de las dos formas de interacción entre el cliente y el servidor según el método de sesión y JWT utilizado en javaWeb y varios proyectos para la autenticación de usuarios.

El uso de Session en el proyecto.

1. Use la sesión para la verificación de inicio de sesión del usuario

El código es solo un ejemplo, solo para referencia.También
hay conexiones de base de datos y configuraciones de archivos yml.
Esta publicación de blog es solo una breve introducción, y también se trata de revisar y consolidar el conocimiento de la autenticación de inicio de sesión.

1. Primero, la clase de usuario [Mapper ya no se presentará]

@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="User对象", description="用户表")
public class User implements Serializable {
    
    

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "用户id")
    @TableId
    private Long userId;

    @ApiModelProperty(value = "用户名称")
    private String username;

    @ApiModelProperty(value = "电话")
    private String phone;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "如果用户传入头像,则用用户的;如果没传,则默认")
    private String avatar;

    @ApiModelProperty(value = "用户介绍")
    private String description;

    @ApiModelProperty(value = "普通用户是0,管理员是1")
    private Integer roles;

    @ApiModelProperty(value = "创建时间")
    private LocalDateTime createTime;

    @ApiModelProperty(value = "修改时间")
    private LocalDateTime updateTime;

    @ApiModelProperty(value = "逻辑删除字段:0 未删除,1 删除")
    private Integer isDelete;


}

2. Cree interfaces de inicio y cierre de sesión

	/**
     * 登录
     *
     * 这里需要说明的是:
     * UserQueryResp 是特殊返回类,包含指定返回内容
     * UserLoginReq  是特殊请求类,包含指定请求内容
     */
    UserQueryResp login(UserLoginReq req, HttpSession session);
	/**
     * 注销
     *
     * @param session 会话
     */
    void logOut(HttpSession session);

3. Escriba código en la clase de implementación de la interfaz de inicio de sesión

El tema de hoy es Sesión, por lo que en el código
session.setAttribute(SESSION_KEYWORDS, userSession);
es establecer la Sesión del usuario actual. Cuando el usuario inicia sesión, después de pasar el interceptor [escrito a continuación], el servidor generará una sesión y devolverá el SeesionID al navegador.

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author yzh
 * @since 2022-08-13
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    

    @Resource
    private UserMapper userMapper;

    @Resource
    private CommonService commonService;

	/**
     * 登录
     * yzh
     * 代码中使用了
     * 1、MyBatis-Plus的条件查询
     * 2、自定义异常 BusinessException
     * 3、枚举类-异常值 BusinessCode
     * 4、Md5 加密处理  DigestUtils.md5DigestAsHex()
     * 5、自定义拷贝类  CopyUtil.copy【类似于BeanUtils的copyproperties方法】
     */
    @Override
    public UserQueryResp login(UserLoginReq req, HttpSession session) {
    
    
        //1、 根据phone查询数据库是否有此用户
        User userDb = this.getOne(Wrappers.lambdaQuery(User.class).eq(User::getPhone, req.getPhone()));
        // 如果数据库中无此用户
        if (ObjectUtils.isEmpty(userDb)){
    
    
            // 前端显示错误原因
            throw new BusinessException(BusinessCode.LOGIN_ERROR,BusinessCode.LOGIN_ERROR.getMessage());
        }

        // 2、对比判断输入密码是否正确
        String reqPwd = DigestUtils.md5DigestAsHex((req.getPassword() + SALT).getBytes());
        if (!reqPwd.equals(userDb.getPassword())){
    
    
            throw new BusinessException(BusinessCode.LOGIN_ERROR,BusinessCode.LOGIN_ERROR.getMessage());
        }
        // 3、将当前用户信息存入session
        User userSession = new User();
        userSession.setUserId(userDb.getUserId());// 拦截器要用到
        session.setAttribute(SESSION_KEYWORDS,userSession);

        return CopyUtil.copy(userDb,UserQueryResp.class);

    }

    /**
     * 退出登录
     *
     * 退出登录,直接调用HttpSession的removeAttribute()方法
     */
    @Override
    public void logOut(HttpSession session) {
    
    
        session.removeAttribute(SESSION_KEYWORDS);
    }
 }

4. Escribir código en el controlador de inicio de sesión Controlador

En el código del controlador, se llama a la operación lógica de la clase de implementación para proporcionar una interfaz para la llamada de front-end

/**
*yzh
*/
@RestController
@RequestMapping("/user")
@Api(tags = "用户接口")
public class UserController {
    
    

    @Resource
    private UserService userService;

	/**
	* @Valid校验
	* @RequestBody  适应JSON格式
	* CommonResponse 自定义的通用返回类
	*/
	@PostMapping("/login")
    @ApiOperation("用户登录")
    public CommonResponse<UserQueryResp> login(@RequestBody @Valid UserLoginReq req, HttpSession session){
    
    
        return CommonResponse.success(userService.login(req,session),"用户登录成功!");
    }


    @PostMapping("/logout")
    @ApiOperation("退出登录")
    public CommonResponse<String> logOut(HttpSession session){
    
    
        userService.logOut(session);
        return CommonResponse.success("用户退出登录成功!");
    }
}    

5. Escribir código en el interceptor

HttpSession session = request.getSession();
User sessionUser = (User) session.getAttribute(SESSION_KEYWORDS);
Este código es para obtener el usuario actual a través de la sesión y determinar el usuario único

/**
 * 登录拦截器
 *
 * @author yzh
 * @since 2022/8/16
 */
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    
    
    @Resource
    private UserMapper userMapper;

    /**
     * 前处理  进行拦截处理
     *
     * HttpSession session = request.getSession();
       User sessionUser = (User) session.getAttribute(SESSION_KEYWORDS);
       这段代码就是通过Session来获取当前用户,确定唯一用户
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        log.info("-------start interceptor------");

        // 通过session得到当前用户,进行操作
        HttpSession session = request.getSession();
        User sessionUser = (User) session.getAttribute(SESSION_KEYWORDS);
        if (ObjectUtils.isEmpty(sessionUser)){
    
    
            throw new BusinessException(BusinessCode.USER_MESSAGE_ERROR,"此用户未登录!");
        }
        // 将处理程序封装为HandlerMethod
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        // handlerMethod.hasMethodAnnotation(AdminRole.class)返回boolean值
        // 当返回 true 时,进行鉴别操作
        /*if (sessionUser.getIsDelete()==1){
            throw new BusinessException(BusinessCode.USER_MESSAGE_ERROR,"此用户已被注销,请重试!");
        }*/

        if (handlerMethod.hasMethodAnnotation(AdminRole.class)){
    
    
            // 通过session传入的Id来匹配当前用户信息,得到当前用户对象
            User user = userMapper.selectById(sessionUser.getUserId());
            if (ObjectUtils.isEmpty(user)){
    
    
                throw new BusinessException(BusinessCode.USER_MESSAGE_ERROR,"此用户不存在!");
            }
            if (!user.getRoles().equals(ADMIN_ROLE)){
    
    
                throw new BusinessException(BusinessCode.USER_MESSAGE_ERROR,"此用户无权限!");
            }
        }
        return true;
    }
}

La sesión también se usa en otros módulos, pero solo se muestra tanto
como la actualización del usuario, la compra de artículos, etc., es necesario verificar si es el usuario actual a través de la sesión.

6. Algunas de las clases anteriores

Respuesta común

/**
 * 公共返回类
 *
 * @author yzh
 * @date 2022/08/15
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResponse<T> implements Serializable {
    
    
    private static final long serialVersionUID = 112345679815613L;

    private boolean success;

    private T data;

    private String message;

    /**
     * 成功
     *
     * @return {@link CommonResponse}<{@link T}>
     */
    public static <T> CommonResponse<T> success(T data, String message) {
    
    
        return new CommonResponse<>(true, data, message);
    }

    /**
     * 成功
     *
     * @return {@link CommonResponse}<{@link T}>
     */
    public static <T> CommonResponse<T> success(String message) {
    
    
        return new CommonResponse<>(true, null, message);
    }

    /**
     * 成功
     *
     * @return {@link CommonResponse}<{@link T}>
     */
    public static <T> CommonResponse<T> success() {
    
    
        return new CommonResponse<>(true, null, "");
    }

    /**
     * 错误
     *
     * @param code    代码
     * @param message 消息
     * @return {@link CommonResponse}<{@link Object}>
     */
    public static CommonResponse<Object> error(BusinessCode code, String message) {
    
    
        return new CommonResponse<>(false, code.getMessage(), message);
    }


}

BusinessException

/**
 * 业务异常
 *
 * @author yzh
 * @date 2022/08/15
 */
public class BusinessException extends RuntimeException {
    
    

    private final BusinessCode businessCode;
    private final String message;

    public BusinessException(BusinessCode businessCode, String message) {
    
    
        this.businessCode = businessCode;
        this.message = message;
    }

    @Override
    public String getMessage() {
    
    
        return message;
    }

    public BusinessCode getBusinessCode() {
    
    
        return businessCode;
    }

    @Override
    public Throwable fillInStackTrace() {
    
    
        return this;
    }
}

Código de negocio

/**
 * 业务代码
 *
 * @author yzh
 * @date 2022/08/15
 */
public enum BusinessCode {
    
    

    PARAM_ERROR("参数错误"),

    LOGIN_ERROR("账号或密码错误"),

    USER_MESSAGE_ERROR("此用户信息错误"),

    AUTH_ERROR("权限错误"),

    FILE_ERROR("文件异常"),

    ASSESS_ERROR("评价异常"),

    BUY_ERROR("购买异常"),

    PRODUCT_ERROR("商品异常")

    ;

    private final String message;

    BusinessCode(String message) {
    
    
        this.message = message;
    }

    public String getMessage() {
    
    
        return message;
    }
}

CopyUtil

package com.yzh.utils;

import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 复制工具类
 *
 * @author yzh
 * @since 2022/08/05
 */
public class CopyUtil {
    
    

    /**
     * 单体复制
     *
     * @param source 源
     * @param clazz  clazz
     * @return {@link T}
     */
    public static <T> T copy(Object source, Class<T> clazz) {
    
    
        if (source == null) {
    
    
            return null;
        }
        T obj;
        try {
    
    
            obj = clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return null;
        }
        BeanUtils.copyProperties(source, obj);
        return obj;
    }

    /**
     * 列表复制
     *
     * @param source 源
     * @param clazz  clazz
     * @return {@link List}<{@link T}>
     */
    public static <T> List<T> copyList(List<?> source, Class<T> clazz) {
    
    
        List<T> target = new ArrayList<>();
        if (!CollectionUtils.isEmpty(source)) {
    
    
            for (Object c : source) {
    
    
                T obj = copy(c, clazz);
                target.add(obj);
            }
        }
        return target;
    }
}

El uso de JWT en el proyecto.

1. Simplemente use JWT

1. Crear una nueva clase de entidad

@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    
    
    private Integer id;
    private String name;
    private String password;
}

2. capa dao

@Mapper
public interface UserDao {
    
    

    /**
     * 登录方法
     * @param user
     * @return
     */
    User login(User user);
}


3. Archivo UserDao.xml

Nota: La ruta debe ser correcta

La ruta establecida en application.properties también debe ser correcta

mybatis.type-aliases-package=com.lut.entity
mybatis.mapper-locations=classpath:mapper/*.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.lut.dao.UserDao">

    <select id="login"  parameterType="User" resultType="User">
        select id,name,password from user where name=#{name} and password=#{password}
    </select>

</mapper>

4. capa de servicio

@Service
public interface UserService {
    
    
    /**
     * 登录方法
     * @param user
     * @return
     */
    User login(User user);
}


@Service
@Transactional
public class UserServiceImpl implements UserService {
    
    

    @Autowired
    private UserDao userDao;


    @Override
    public User login(User user) {
    
    
        //接受用户查询数据库
        User userDB = userDao.login(user);

        //查询到这个用户就返回,没有则抛出错误
        if (userDB != null) {
    
    
            return userDB;
        }else{
    
    
            throw new RuntimeException("登录失败!");
        }
    }


}

5. Capa del controlador

@RestController
@Slf4j
public class UserController {
    
    

    @Autowired
    private UserService userService;

    @GetMapping("/test")
    public String test(User user) {
    
    
        return "ok";
    }


    @GetMapping("/user/login")
    public Map<String, Object> login(User user) {
    
    
        log.info("用户名:[{}]", user.getName());
        log.info("密码:[{}]", user.getPassword());
        HashMap<String, Object> map = new HashMap<>();

        try {
    
    
            //获取user对象
            User userDB = userService.login(user);
            //将user对象添加到map
            Map<String, String> payload = new HashMap<>();
            payload.put("id", userDB.getId().toString());
            payload.put("name", userDB.getName());
            //生成令牌
            String token = JWTUtils.getToken(payload);
            
            map.put("state", true);
            map.put("msg", "认证成功");
            map.put("token", token);

        } catch (Exception e) {
    
    
            map.put("state", false);
            map.put("msg", e.getMessage());
        }

        return map;
    }
    

    @PostMapping("/user/test")
    public Map<String, Object> test(String token) {
    
    
        Map<String, Object> map = new HashMap<>();
        log.info("当前token为:[{}]", token);

        try {
    
    
            DecodedJWT verify = JWTUtils.verify(token);
            map.put("state", true);
            map.put("msg", "请求成功");
            return map;
        } catch (SignatureVerificationException e) {
    
    
            map.put("msg", "签名不一致异常");
            e.printStackTrace();
        } catch (TokenExpiredException e) {
    
    
            map.put("msg", "令牌过期异常");
            e.printStackTrace();
        } catch (AlgorithmMismatchException e) {
    
    
            map.put("msg", "算法不匹配异常");
            e.printStackTrace();
        } catch (Exception e) {
    
    
            map.put("msg", "token无效");
            e.printStackTrace();
        }

        map.put("state", false);
        return map;
    }


}

6. Prueba

Puedes usar ApiFox o Postman

7. interceptor

Decide qué bloquear

el código es solo para demostración

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    
    

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        //只做示例
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/user/test") //其他接口保护
                .excludePathPatterns("/user/login");//所有用户接口放行

    }
}


Interceptar antes de procesar la ruta


public class Login	Interceptor implements HandlerInterceptor {
    
    

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    

        Map<String,Object> map=new HashMap<>();
        //获取请求头中的令牌
        String token=request.getHeader("token");

        try {
    
    
            //验证令牌
            JWTUtils.decodedJWT(token);
            //放行请求
            return true;
        } catch (SignatureVerificationException e) {
    
    
            map.put("msg", "签名不一致异常");
            e.printStackTrace();
        } catch (TokenExpiredException e) {
    
    
            map.put("msg", "令牌过期异常");
            e.printStackTrace();
        } catch (AlgorithmMismatchException e) {
    
    
            map.put("msg", "算法不匹配异常");
            e.printStackTrace();
        } catch (Exception e) {
    
    
            map.put("msg", "token无效");
            e.printStackTrace();
        }

        map.put("state",false);
        //将map 转为 json
        String json=new ObjectMapper().writeValueAsString(map);
        response.setContentType("appliaction/json;charset=UTF-8");
        return false;

    }
}

Resultados de la prueba
Lo mejor es encapsular el token en el encabezado

2. Combinar la autenticación de usuarios de Spring Security y la gestión de autoridad

no todavía

Supongo que te gusta

Origin blog.csdn.net/AN_NI_112/article/details/131502664
Recomendado
Clasificación