把數(shù)據(jù)庫里的未付款訂單改成已付款息堂,會發(fā)生什么

導言

不知道大家在網(wǎng)上購物的時候嚷狞,有沒有這樣的念頭块促,如果能把未付款的訂單偷偷用一條SQL改成已付款,該多么美好啊床未。那么在實際開發(fā)過程中竭翠,我們應當如何保證數(shù)據(jù)庫里的數(shù)據(jù)在保存后不會被偷偷更改?

大家好我是日暮與星辰之間薇搁,創(chuàng)作不易斋扰,如果覺得有用,求點贊啃洋,求收藏传货,求轉發(fā),謝謝宏娄。

理論

在介紹具體的內容之間问裕,先介紹MD5算法,簡單的來說孵坚,MD5能把任意大小粮宛、長度的數(shù)據(jù)轉換成固定長度的一串字符,經常玩大型游戲的朋友應該都注意到過卖宠,各種補丁包窟勃、端游客戶端之類的大型文件一般都附有一個MD5值,用于確保你下載文件的完整性逗堵。那么在這里秉氧,我們可以借鑒其思想,對訂單的某些屬性進行加密計算蜒秤,得出來一個 MD5值一并保存在數(shù)據(jù)庫當中汁咏。從數(shù)據(jù)庫取出數(shù)據(jù)后第一時間進行校驗,如果有異常更改作媚,那么及時拋出異常進行人工處理攘滩。

實現(xiàn)

道理我都懂,但是我要如何做呢纸泡,別急漂问,且聽我一一道來。

這種需求聽起來并不強綁定于某個具體的業(yè)務需求女揭,這就要用到了我們熟悉的鼎鼎有名的AOP(面向切面編程)來實現(xiàn)蚤假。

首先定義四個類型的注解作為AOP的切入點。@Sign@Validate都是作用在方法層面的吧兔,分別用于對方法的入?yún)⑦M行加簽和驗證方法的返回值的簽名磷仰。@SignField用于注解關鍵的不容篡改的字段。@ValidateField用于注解保存計算后得出的簽名值境蔼。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sign {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate {
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SignField {
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidField {
}

以訂單的實體為例 sn,amt,status,userId就是關鍵字段灶平,絕不能允許有人在落單到數(shù)據(jù)庫后對這些字段偷偷篡改伺通。

public class Order {
    @SignField
    private String sn;
    @SignField
    private String amt;
    @SignField
    private int status;
    @SignField
    private int userId;
    @ValidField
    private String sign;
}

下面就到了重頭戲的部分,如何通過AOP來進行實現(xiàn)逢享。

1. 定義切入點

@Pointcut("execution(@com.example.demo.annotations.Sign * *(..))")
public void signPointCut() {

}

@Pointcut("execution(@com.example.demo.annotations.Validate * *(..))")
public void validatePointCut() {

}

2.環(huán)繞切入點

@Around("signPointCut()")
public Object signAround(ProceedingJoinPoint pjp) throws Throwable {
    Object[] args = pjp.getArgs();
    for (Object o : args) {
        System.out.println(o);
        sign(o);
    }
    Object res = pjp.proceed(args);
    return res;
}

@Around("validatePointCut()")
public Object validateAround(ProceedingJoinPoint pjp) throws Throwable {
    Object[] args = pjp.getArgs();
    Object res = pjp.proceed(args);
    valid(res);
    return res;
}

3. 簽名的實現(xiàn)

1.獲取需要簽名字段

private Map<String, String> getSignMap(Object o) throws IllegalAccessException {
    Map<String, String> fieldNameToValue = new HashMap<>();
    for (Field f : o.getClass().getDeclaredFields()) {
        System.out.println(f.getName());
        for (Annotation annotation : f.getDeclaredAnnotations()) {
            if (annotation.annotationType().equals(SignField.class)) {
                String value = "";
                f.setAccessible(true);
                fieldNameToValue.put(f.getName(), f.get(o).toString());
            }
        }
    }
    return fieldNameToValue;
}

2.計算出簽名值罐监,這里在屬性名和屬性值以外加入了我的昵稱以防止他人猜測,同時使用了自定義的分隔符來加強密碼強度瞒爬。

private String getSign(Map<String, String> fieldNameToValue) {
    List<String> names = new ArrayList<>(fieldNameToValue.keySet());
    StringBuilder sb = new StringBuilder();
    for (String name : names)
        sb.append(name).append("@").append(fieldNameToValue.get(name));
    System.out.println(sb.append("日暮與星辰之間").toString());
    String signValue = DigestUtils.md5DigestAsHex(sb.toString().getBytes(StandardCharsets.UTF_8));
    return signValue;
}
  1. 找到保存簽名的字段
private Field getValidateFiled(Object o) {
    for (Field f : o.getClass().getDeclaredFields()) {
        for (Annotation annotation : f.getDeclaredAnnotations()) {
            if (annotation.annotationType().equals(ValidField.class)) {
                return f;
            }
        }
    }
    return null;
}
  1. 對保存簽名的字段進行賦值
public void sign(Object o) throws IllegalAccessException {
    Map<String, String> fieldNameToValue = getSignMap(o);
    if (fieldNameToValue.isEmpty()) {
        return;
    }
    Field validateField = getValidateFiled(o);
    if (validateField == null)
        return;
    String signValue = getSign(fieldNameToValue);
    validateField.setAccessible(true);
    validateField.set(o, signValue);
}
  1. 對從數(shù)據(jù)庫中取出的對象進行驗證
public void valid(Object o) throws IllegalAccessException {
    Map<String, String> fieldNameToValue = getSignMap(o);
    if (fieldNameToValue.isEmpty()) {
        return;
    }
    Field validateField = getValidateFiled(o);
    validateField.setAccessible(true);
    String signValue = getSign(fieldNameToValue);
    if (!Objects.equals(signValue, validateField.get(o))) {
        throw new RuntimeException("數(shù)據(jù)非法");
    }

}

使用示例

對將要保存到數(shù)據(jù)庫的對象進行簽名

@Sign
public Order save( Order order){
    orderList.add(order);
    return order;
}

驗證從數(shù)據(jù)庫中取出的對象是否合理

@Validate
public Order query(@ String sn){
   return orderList.stream().filter(e -> e.getSn().equals(sn)).findFirst().orElse(null);
}

本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布笑诅!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市疮鲫,隨后出現(xiàn)的幾起案子吆你,更是在濱河造成了極大的恐慌,老刑警劉巖俊犯,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妇多,死亡現(xiàn)場離奇詭異,居然都是意外死亡燕侠,警方通過查閱死者的電腦和手機者祖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绢彤,“玉大人七问,你說我怎么就攤上這事∶2埃” “怎么了械巡?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長饶氏。 經常有香客問我讥耗,道長,這世上最難降的妖魔是什么疹启? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任古程,我火速辦了婚禮,結果婚禮上喊崖,老公的妹妹穿的比我還像新娘挣磨。我一直安慰自己荤懂,他們只是感情好茁裙,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著势誊,像睡著了一般呜达。 火紅的嫁衣襯著肌膚如雪谣蠢。 梳的紋絲不亂的頭發(fā)上粟耻,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天查近,我揣著相機與錄音,去河邊找鬼挤忙。 笑死霜威,一個胖子當著我的面吹牛,可吹牛的內容都是我干的册烈。 我是一名探鬼主播戈泼,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赏僧!你這毒婦竟也來了大猛?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤淀零,失蹤者是張志新(化名)和其女友劉穎挽绩,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驾中,經...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡唉堪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肩民。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唠亚。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖持痰,靈堂內的尸體忽然破棺而出灶搜,到底是詐尸還是另有隱情,我是刑警寧澤工窍,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布占调,位于F島的核電站,受9級特大地震影響移剪,放射性物質發(fā)生泄漏究珊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一纵苛、第九天 我趴在偏房一處隱蔽的房頂上張望剿涮。 院中可真熱鬧,春花似錦攻人、人聲如沸取试。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瞬浓。三九已至,卻和暖如春蓬坡,著一層夾襖步出監(jiān)牢的瞬間猿棉,已是汗流浹背磅叛。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萨赁,地道東北人弊琴。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像杖爽,于是被迫代替她去往敵國和親敲董。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內容