ソースを参照

管理员模块开发

wangzhengliang 3 年 前
コミット
db10f6c06f

+ 56 - 30
src/main/java/com/chuanghai/ihotel/controller/HotelStaffController.java

@@ -1,23 +1,28 @@
 package com.chuanghai.ihotel.controller;
 
-import java.util.Arrays;
-
+import com.chuanghai.ihotel.anno.AdminLoginCheck;
+import com.chuanghai.ihotel.anno.ParamCheck;
+import com.chuanghai.ihotel.common.exception.BizCodeEnume;
+import com.chuanghai.ihotel.common.exception.RRException;
+import com.chuanghai.ihotel.common.utils.CommonResult;
+import com.chuanghai.ihotel.common.utils.PageParam;
+import com.chuanghai.ihotel.common.utils.PageUtils;
+import com.chuanghai.ihotel.controller.request.AdminLoginRequest;
+import com.chuanghai.ihotel.entity.HotelStaffEntity;
+import com.chuanghai.ihotel.service.HotelStaffService;
+import com.chuanghai.ihotel.vo.LoginUserVO;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import com.chuanghai.ihotel.entity.HotelStaffEntity;
-import com.chuanghai.ihotel.service.HotelStaffService;
-import com.chuanghai.ihotel.common.utils.PageUtils;
-import com.chuanghai.ihotel.common.utils.CommonResult;
-import com.chuanghai.ihotel.common.utils.PageParam;
-
+import java.util.Arrays;
 
 /**
  * 酒店员工 
@@ -33,41 +38,63 @@ public class HotelStaffController {
     private HotelStaffService hotelStaffService;
 
     /**
-     * 列表
+     * 管理员登录
+     * @param request
+     * @return
+     * @apiNote 注意:密码使用提供的公钥进行RSA加密后传输
+     * 公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMOcPB06u5yKyQsPjfVWiWgbEIrd14kiXNNihciaVKb6HnkQvq7zpQuZ80WEX94spnUMI3iOAl/GmIvHrpGwcbB4hJbznm+PajiwnUSPuCCXA68YJF640cJKb/8KeM7WVz69OFkIEPHhVxOy4FFF5QWe/kt6zOZ19HmE+ak+5x/QIDAQAB
      */
-    @GetMapping("/list")
-    public CommonResult<PageUtils<HotelStaffEntity>> list(PageParam pageParam){
-        PageUtils page = hotelStaffService.queryPage(pageParam);
-
-        return CommonResult.ok().setResult(page);
+    @ParamCheck
+    @PostMapping("login")
+    public CommonResult<LoginUserVO> login(@RequestBody AdminLoginRequest request) {
+        LoginUserVO vo = hotelStaffService.login(request);
+        return CommonResult.ok().setResult(vo);
     }
 
-
     /**
-     * 信息
+     * 管理员列表
+     * @param adminToken 管理员token
+     * @param pageParam 分页参数
+     * @return
      */
-    @GetMapping("/info/{id}")
-    public CommonResult<HotelStaffEntity> info(@PathVariable("id") Long id){
-		HotelStaffEntity hotelStaff = hotelStaffService.getById(id);
+    @AdminLoginCheck
+    @GetMapping("/list")
+    public CommonResult<PageUtils<HotelStaffEntity>> list(@RequestHeader("admin_token") String adminToken,
+                                                         PageParam pageParam){
+        PageUtils page = hotelStaffService.queryPage(pageParam);
 
-        return CommonResult.ok().setResult(hotelStaff);
+        return CommonResult.ok().setResult(page);
     }
 
     /**
-     * 保存
+     * 新增管理员
+     * @param adminToken 管理员token
+     * @param staffEntity 管理员信息
+     * @return
      */
-    @PostMapping("/save")
-    public CommonResult<String> save(@RequestBody HotelStaffEntity hotelStaff){
-		hotelStaffService.save(hotelStaff);
+    @AdminLoginCheck
+    @ParamCheck(index = {2})
+    @PostMapping("/add")
+    public CommonResult<String> add(@RequestHeader("admin-token") String adminToken,
+                                     @RequestBody HotelStaffEntity staffEntity){
+
+        String password = staffEntity.getPassword();
+        if (!StringUtils.hasText(password)) {
+            throw new RRException(BizCodeEnume.PARAMETER_ERROR, "密码不能为空");
+        }
 
+        hotelStaffService.mySave(staffEntity);
         return CommonResult.ok();
     }
 
     /**
-     * 修改
+     * 修改管理员
      */
+    @AdminLoginCheck
+    @ParamCheck
     @PutMapping("/update")
     public CommonResult<String> update(@RequestBody HotelStaffEntity hotelStaff){
+        hotelStaff.setPassword(null);
 		boolean flag = hotelStaffService.updateById(hotelStaff);
 
 		if (flag) {
@@ -78,17 +105,16 @@ public class HotelStaffController {
     }
 
     /**
-     * 删除
+     * 删除管理员
      */
+    @AdminLoginCheck
     @DeleteMapping("/delete")
     public CommonResult<String> delete(@RequestBody Long[] ids){
         boolean flag = hotelStaffService.removeByIds(Arrays.asList(ids));
-
         if (flag) {
             return CommonResult.ok();
         } else {
             return CommonResult.fail();
         }
     }
-
 }

+ 26 - 0
src/main/java/com/chuanghai/ihotel/controller/request/AdminLoginRequest.java

@@ -0,0 +1,26 @@
+package com.chuanghai.ihotel.controller.request;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @Author: codingliang
+ * @Description: 管理员登录
+ * @Date: 2022-08-04 14:54
+ * @Version: V1.0
+ **/
+@Data
+public class AdminLoginRequest {
+
+    /**
+     * 用户名
+     */
+    @NotBlank(message = "用户名不能为空")
+    private String username;
+    /**
+     * 密码
+     */
+    @NotBlank(message = "密码不能为空")
+    private String password;
+}

+ 9 - 1
src/main/java/com/chuanghai/ihotel/entity/HotelStaffEntity.java

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
 import java.io.Serializable;
 
 /**
@@ -26,26 +28,32 @@ public class HotelStaffEntity implements Serializable {
 	/**
 	 * 员工卡号 微校card_number
 	 */
+	@NotBlank(message = "员工卡号不能为空")
 	private String cardNumber;
 	/**
 	 * 手机号码 登录账号
 	 */
+	@NotBlank(message = "手机号码不能为空")
 	private String phone;
 	/**
 	 * 员工姓名
 	 */
+	@NotBlank(message = "员工姓名不能为空")
 	private String username;
 	/**
 	 * 职位
 	 */
+	@NotBlank(message = "职位不能为空")
 	private String position;
 	/**
-	 * 密码 登录密码
+	 * 密码 登录密码,新增时不能为空,使用RSA加密后传输
 	 */
 	private String password;
 	/**
 	 * 状态 0冻结、1正常
 	 */
+	@NotBlank(message = "状态不能为空")
+	@Pattern(regexp = "[1-2]", message = "状态只能为1或2")
 	private String statu;
 
 }

+ 11 - 0
src/main/java/com/chuanghai/ihotel/service/HotelStaffService.java

@@ -3,7 +3,9 @@ package com.chuanghai.ihotel.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.chuanghai.ihotel.common.utils.PageUtils;
 import com.chuanghai.ihotel.common.utils.PageParam;
+import com.chuanghai.ihotel.controller.request.AdminLoginRequest;
 import com.chuanghai.ihotel.entity.HotelStaffEntity;
+import com.chuanghai.ihotel.vo.LoginUserVO;
 
 /**
  * 酒店员工 
@@ -15,5 +17,14 @@ import com.chuanghai.ihotel.entity.HotelStaffEntity;
 public interface HotelStaffService extends IService<HotelStaffEntity> {
 
     PageUtils queryPage(PageParam pageParam);
+
+    /**
+     * 登录
+     * @param request
+     * @return
+     */
+    LoginUserVO login(AdminLoginRequest request);
+
+    void mySave(HotelStaffEntity staffEntity);
 }
 

+ 59 - 1
src/main/java/com/chuanghai/ihotel/service/impl/HotelStaffServiceImpl.java

@@ -1,5 +1,14 @@
 package com.chuanghai.ihotel.service.impl;
 
+import com.chuanghai.ihotel.common.exception.BizCodeEnume;
+import com.chuanghai.ihotel.common.exception.RRException;
+import com.chuanghai.ihotel.controller.request.AdminLoginRequest;
+import com.chuanghai.ihotel.dto.LoginUserDTO;
+import com.chuanghai.ihotel.util.JWTUtil;
+import com.chuanghai.ihotel.util.RSAUtils;
+import com.chuanghai.ihotel.vo.LoginUserVO;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.stereotype.Service;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -16,14 +25,63 @@ import com.chuanghai.ihotel.service.HotelStaffService;
 @Service("hotelStaffService")
 public class HotelStaffServiceImpl extends ServiceImpl<HotelStaffDao, HotelStaffEntity> implements HotelStaffService {
 
+    @Value("${my-security.private-key}")
+    private String privateKey;
+
     @Override
     public PageUtils queryPage(PageParam pageParam) {
         IPage<HotelStaffEntity> page = this.page(
                 new MyQuery<HotelStaffEntity>().getPage(pageParam),
-                new QueryWrapper<HotelStaffEntity>()
+                new QueryWrapper<>()
         );
 
         return new PageUtils(page);
     }
 
+    @Override
+    public LoginUserVO login(AdminLoginRequest request) {
+        QueryWrapper<HotelStaffEntity> wrapper = new QueryWrapper<>();
+        wrapper.eq("username", request.getUsername());
+        wrapper.last("limit 1");
+        HotelStaffEntity staff = this.getOne(wrapper);
+        if (staff == null) {
+            throw new RRException(BizCodeEnume.ADMIN_LOGIN_FAIL);
+        }
+        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+        String password = null;
+        try {
+            password = RSAUtils.decrypt(request.getPassword(), RSAUtils.getPrivateKey(privateKey));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        if (!encoder.matches(password, staff.getPassword())) {
+            throw new RRException(BizCodeEnume.ADMIN_LOGIN_FAIL);
+        }
+
+        // 登录成功,生成token
+        LoginUserDTO dto = LoginUserDTO.builder().adminId(staff.getId()).userType("1").build();
+        String token = JWTUtil.geneJsonWebToken(dto);
+
+        // 生成vo
+        return LoginUserVO.builder()
+                .token(token)
+                .tokenTtl(JWTUtil.getExpired())
+                .userName(staff.getUsername())
+                .userType("1")
+                .build();
+    }
+
+    @Override
+    public void mySave(HotelStaffEntity staffEntity) {
+        String password;
+        try {
+            password = RSAUtils.decrypt(staffEntity.getPassword(), RSAUtils.getPrivateKey(privateKey));
+        } catch (Exception e) {
+            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "新增用户失败-密码解密错误");
+        }
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        staffEntity.setPassword(passwordEncoder.encode(password));
+        this.save(staffEntity);
+    }
+
 }

+ 180 - 0
src/main/java/com/chuanghai/ihotel/util/RSAUtils.java

@@ -0,0 +1,180 @@
+package com.chuanghai.ihotel.util;
+
+import org.apache.tomcat.util.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+
+/**
+ * @Author: codingliang
+ * @Description: TODO
+ * @Date: 2022-08-04 10:53
+ * @Version: V1.0
+ **/
+public class RSAUtils {
+
+    /**
+     * RSA最大加密明文大小
+     */
+    private static final int MAX_ENCRYPT_BLOCK = 117;
+    /**
+     * RSA最大解密密文大小
+     */
+    private static final int MAX_DECRYPT_BLOCK = 128;
+    private static final String ALGORITHM_NAME = "RSA";
+    private static final String MD5_RSA = "MD5withRSA";
+
+    /**
+     * 获取密钥对
+     */
+    public static KeyPair getKeyPair() throws Exception {
+        KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM_NAME);
+        generator.initialize(1024);
+        return generator.generateKeyPair();
+    }
+
+    /**
+     * 获取base64加密后密钥对
+     */
+    public static HashMap<String, String> getKeyPairMap() throws Exception {
+        KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM_NAME);
+        generator.initialize(1024);
+        KeyPair keyPair = generator.generateKeyPair();
+        String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
+        String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
+        HashMap<String, String> keyMap = new HashMap<>();
+        keyMap.put("privateKey", privateKey);
+        keyMap.put("publicKey", publicKey);
+        return keyMap;
+    }
+
+
+    /**
+     * 获取公钥
+     * @param publicKey base64加密的公钥字符串
+     */
+    public static PublicKey getPublicKey(String publicKey) throws Exception {
+        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
+        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
+        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
+        return keyFactory.generatePublic(keySpec);
+    }
+
+
+    /**
+     * RSA加密
+     *
+     * @param data      待加密数据
+     * @param publicKey 公钥
+     */
+    public static String encrypt(String data, PublicKey publicKey) throws Exception {
+        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
+        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+        int inputLen = data.getBytes().length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offset = 0;
+        byte[] cache;
+        int i = 0;
+        // 对数据分段加密
+        while (inputLen - offset > 0) {
+            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
+                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
+            } else {
+                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offset = i * MAX_ENCRYPT_BLOCK;
+        }
+        byte[] encryptedData = out.toByteArray();
+        out.close();
+        // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
+        // 加密后的字符串
+        return new String(Base64.encodeBase64(encryptedData));
+    }
+
+
+    /**
+     * 获取私钥
+     *
+     * @param privateKey base64加密的私钥字符串
+     */
+    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
+        byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
+        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
+        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
+        return keyFactory.generatePrivate(keySpec);
+    }
+
+
+    /**
+     * RSA解密
+     * @param data 待解密数据
+     * @param privateKey 私钥
+     */
+    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
+        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
+        cipher.init(Cipher.DECRYPT_MODE, privateKey);
+        byte[] dataBytes = Base64.decodeBase64(data);
+        int inputLen = dataBytes.length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offset = 0;
+        byte[] cache;
+        int i = 0;
+        // 对数据分段解密
+        while (inputLen - offset > 0) {
+            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
+                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
+            } else {
+                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offset = i * MAX_DECRYPT_BLOCK;
+        }
+        byte[] decryptedData = out.toByteArray();
+        out.close();
+        // 解密后的内容
+        return new String(decryptedData, StandardCharsets.UTF_8);
+    }
+
+
+    public static void main(String[] args) {
+        try {
+
+            // 生成密钥对
+            //KeyPair keyPair = getKeyPair();
+            //String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
+            //String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
+            //System.out.println("私钥 => " + privateKey + "\n");
+            //System.out.println("公钥 =>" + publicKey + "\n");
+
+            HashMap<String, String> keyPairMap = getKeyPairMap();
+            String privateKey = keyPairMap.get("privateKey");
+            String publicKey =  keyPairMap.get("publicKey");
+            System.out.println("私钥 => " + privateKey + "\n");
+            System.out.println("公钥 =>" + publicKey + "\n");
+
+            // RSA加密
+            String data = "123456";
+            String encryptData = encrypt(data, getPublicKey(publicKey));
+            System.out.println("加密后内容 => " + encryptData + "\n");
+            // RSA解密
+            String decryptData = decrypt(encryptData, getPrivateKey(privateKey));
+            System.out.println("解密后内容 => " + decryptData + "\n");
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.err.println("RSA加解密异常");
+        }
+    }
+}

ファイルの差分が大きいため隠しています
+ 4 - 0
src/main/resources/application.yml