背景
私たちのシステムのアクセス許可の検証は、ビジネスロジックは何の関係もありませんが、それはビジネス機能に密接に関連しています。
我々は、システムのメンバーをカスタマイズするために、中小企業のためのビジョンを開発しました。システムは、企業A、Bおよびその他の企業のためのサービスを提供することができます。データベースのテーブル構造(以下は単なるデモで、フィールド内の実際の状況はますます複雑になります)ので、多くの場合、次のとおりです。
ID | memberCardCode | userNameに | card_status | ビジネス |
---|---|---|---|---|
1 | a564456578 | zhangsan | 0 | ビジネス-A |
2 | b678688643 | 溶解 | 1 | businsss-B |
3 | a775445667 | wangwu | 0 | businsss-A |
4 | b943578978 | zhaoliu | 1 | businsss-B |
5 | c657688799 | sunqi | 1 | businsss-C |
:上記の表に基づいて、我々は、ID = 1人のメンバーは、多くの場合、この操作(物理的に削除されると仮定)を除去
コントローラ層。
@RestController("/member")
public class MemberController {
@PostMapping("/delete")
public void deleteById(int id) {
// 此处省略删除代码
}
}
复制代码
このようなコントローラの最後の呼び出しでSQL文:
delete from member where id = 1;
复制代码
一見すると、どんな問題を抱えているために、このような単純なSQL文ですか?実際には、もっと簡単な質問には、より手放すことはできません。
テーブルによって、我々は1がビジネスに属し=会員情報IDを参照してください。あなたが= 1会員情報IDを削除することができ、ビジネス・アカウントであることを想定しています。1へのidパラメータは、その後、ビジネス-Bがあるでしょうビジネス-bの削除メンバーならば、その時点ではビジネスのメンバーを削除しました。このとき、ビジネス・気分のクラッシュ。
無粋:侵襲的なビジネスコード体系
コントローラ層に論理判断を添加した:彼らは、その後削除された場合、現在のアカウントIDを削除するかどうかを決定するために、そうでなければ直接返します。コードは以下の通りであります:
@RestController("/member")
public class MemberController {
@PostMapping("/delete")
public void deleteById(int id) {
// 第一步:权限验证
Integer id = selectByIdAndBusiness(id, "business-a");
if (id == null) {
// 说明id不属于business-a不能删除
return;
}
// 第二步:调用删除逻辑
}
}
复制代码
上記のコードは、越権の問題を解決しないが、いくつかのビジネスは私たちのビジネス・ロジックを侵略するために、コードに依存しない、このロジックは、優雅さを達成することはほとんどありません。その後、我々は完全な権限を確認するために、よりエレガントな方法を選択してください。
エレガント:プログラムの+ノートセクション
idとビジネス:まず、情報の懸念のフィールドをクリアする必要があります。どこで事業をしてThreadLocalのフィルタに保存することができますので、我々は単にフィールドIDに焦点を当てる必要があります。
ステップ1:カスタム注釈を作成します(メソッド演技法)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auth {
// 方法的参数名称,以防参数名称不是id,所以提供paramName
String paramName() default "id";
}
复制代码
ステップ2:メソッドに注釈を使用します
package com.demo.controller;
@RestController("/member")
public class MemberController {
@PostMapping("/delete")
@Auth(paramId = "deleteId")
public void deleteById(int deleteId) {
// 调用删除逻辑
}
}
复制代码
第三段階:態様を実装
// 通过注解可以看到,我们该方法切的是controller层带有Auth注解的方法
@Before(value = "execution(public * com.demo.controller..*.*(..))"
+ " && @annotation(auth)", argNames = "pjp, auth")
public void before4Auth(JoinPoint pjp, Auth auth) {
// 1、通过ThreadLocal获取business
String business = context.get();
// 2、通过注解解析id
// 2.1 获取参数值
Object[] args = pjp.getArgs();
// 2.2 获取参数名
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
String[] parameterNames = methodSignature.getParameterNames();
// 2.3 获取注解中paramName的下标
int index = ArrayUtils.indexOf(parameterNames, auth.paramName());
// 2.4 根据下标获取id对应的值
int val = (int) args[index];
// 2.5 鉴权逻辑
Integer id = selectByIdAndBusiness(val, business);
if (id == null) {
// 抛异常提示越权
}
// 否则的正常执行下面的业务逻辑
}
复制代码
このように、我々は、単にメソッドレイヤコントローラを加えた@Auth
注釈ができます。立ち入り禁止非ビジネスコード、実装はエレガントと考えることができません。
あなたはよりエレガントな解決策を持っている場合は、アイデアを歓迎します。