SpringBoot + interceptor + custom exception + custom annotation + global exception handling, simple interface permission management
https://mp.weixin.qq.com/s/9C5gH28MQECT8n3NBbLdCQ
I think an interceptor plus other processing can meet the needs of the project. Why should I use another framework,
I divide permission management into three parts:
- Resource permissions: using URL as a resource, you can dynamically divide URL permissions for each account to access different URLs;
- Operation permissions: divide all URL s into four operation permissions: add, delete, modify and query, and assign corresponding operation permissions to users. If a user has only query operation permissions, he cannot do other operations;
- Role permissions: the system has multiple roles, and the permissions of each role are different. For example, a management background has an account management module and a commodity module. The role of super administrator can see and operate all modules, while the role of after-sales can only see the commodity module. Even if he knows the URL under the account management module, he has no permission to operate. Then, setting roles for users has corresponding permissions;
Resource permissions
1. Static resource preparation
It's convenient to demonstrate here, so you don't directly operate the database. The corresponding permission table relationship is also very simple. Here, you can directly establish the static URL relationship corresponding to the user.
public class Constant { /** * Authority management */ public static Map<Integer,String[]> permission=new HashMap<>(); static { //URL permissions owned by user 1 String[] frist={"/url1","/url2","/url3","/url4","/url5","/url6","/url7"}; //URL permissions owned by user 2 String[] second={"/url1","/url2","/url3","/url4","/url5"}; //URL permissions owned by user 3 String[] third={"/url1","/url2","/url3"}; permission.put(1,frist); permission.put(2,second); permission.put(3,third); } }
2. Customize an exception to be intercepted and thrown
public class APIException extends RuntimeException { private static final long serialVersionUID = 1L; //Abnormal message private String msg; //Construction assignment public APIException(String msg) { super(msg); this.msg = msg; } }
3. Global exception handling
It is convenient to return unified and standardized results after exceptions. Normally, you should return custom Vo, but the goal here is to demonstrate the results. In addition, you should have your own Vo class, so you don't need it here
@RestControllerAdvice public class WebExceptionControl { @ExceptionHandler(APIException.class) public String APIExceptionHandler(APIException e) { return e.getMessage(); } }
4.controller layer
It's easy to create the corresponding URL
@RestController public class TestController { @RequestMapping(value = "/url1") public String url1() { return "Congratulations, you have this permission"; } @RequestMapping(value = "/url7") public String url7() { return "Congratulations, you have this permission"; } }
5. Interceptor creation
Generally, you need to verify the token first, and then get the user's corresponding information according to the token. There is no login here, so you can directly pass the key value of the corresponding user in the token
/** * Rights management URL interceptor. Cannot public on class */ public class URLInterceptor implements HandlerInterceptor { // The preprocessing callback method uses true to represent release before the interface call, and false to represent no release @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { //Forced to turn a lonely HttpServletRequest httpServletRequest = (HttpServletRequest) request; //Get token String token = httpServletRequest.getHeader("token"); //Gets the uri of the request String requestURL = httpServletRequest.getRequestURI(); //1. Judge whether the user logs in according to the token if (token==null){ //Under normal circumstances, it is also necessary to judge whether it matches the token in redis // If there is no token or the tokens do not match, an exception will be thrown directly to prompt that you are not logged in throw new APIException("The current user is not logged in"); } //2. After successful login, obtain the URL permission set corresponding to the user according to the information in the user token. 1 2 3 get all permissions String[] strings = Constant.permission.get(Integer.valueOf(token)); boolean hasPermission = false; //3. Compare the URL set corresponding to the user with the URL of the current request. If there is a match, it will be released. Otherwise, an exception will be thrown for (int i =0;i<strings.length;i++) { //ergodic if (strings[i].equals(requestURL)){//If the same requestURL //Permission feasible hasPermission = true; break; } } if (hasPermission){ return true; }else { throw new APIException("The current user has no access path" + requestURL + "Permissions for"); } } }
6. Inject the interceptor into the application
@Configuration public class WebMvcConfg implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { //Permission interceptor registry.addInterceptor(urlInterceptor()).addPathPatterns("/**"); } @Bean public URLInterceptor urlInterceptor(){ return new URLInterceptor(); } }
7. Verify and view the results
Pass in the key s of users 1-3 in the token respectively. You can see the effect by visiting different URLs, as shown below
Replace the token with 1 to display:
Congratulations, you have this permission
Operation authority
1. Use static resources as above
public class Constant { /** * Authority management */ public static Map<Integer,String[]> permission=new HashMap<>(); static { String[] frist={"insert","delete","select","update"};//Operation permissions owned by user 1 String[] second={"insert","select","update"};//URL permissions owned by user 2 String[] third={"select"};//URL permissions owned by user 3 permission.put(1,frist); permission.put(2,second); permission.put(3,third); } }
2. User defined annotation
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface UrlAnnotation { /** * Operation type: add, delete, modify, insert * */ String type(); }
3.controller layer
It is marked with user-defined annotation to represent the operation of the corresponding method
4. Modify the previous interceptor
Add the acquisition of the operation type above the annotation, and use the type type to compare and judge
//Strong rotation HandlerMethod handlerMethod = (HandlerMethod) handler; //Acquisition method Method method = handlerMethod.getMethod(); //Get action annotation UrlAnnotation urlAnnotation = method.getAnnotation(UrlAnnotation.class); //If the obtained is null if (null == urlAnnotation) { throw new APIException("The current user has no access path" + requestURL + "Permissions for"); } //@UrlAnnotation(type = "select") gets the type String type = urlAnnotation.type(); //2. After successful login, obtain the URL permission set corresponding to the user according to the information in the user token. 1 2 3 get all permissions String[] strings2 = Constant.permissionCRUD.get(Integer.valueOf(token)); boolean hasPermission2 = false; //If you have permission on action in the array, you can access it for (int i = 0; i < strings2.length; i++) { if (strings2[i].equals(type)) { //Permission feasible hasPermission2 = true; break; } }
5. Verification results
Everything else remains the same
http://localhost:8080/url1 . token=2, 2 users, with query permission. Interface 1 is a query
Congratulations, you have this permission
Role permissions
In fact, the operations here are similar to those above. Let me briefly demonstrate here, taking two modules as examples
1. Static correspondence
public class Constant { /** * Authority management */ public static Map<Integer,String[]> permission=new HashMap<>(); static { String[] frist={"test","test1"};//Module permissions owned by user 1. Test here is the module URL entry. For example, all URLs under the test module are / test/** String[] second={"test"};//Module permissions owned by user 2 permission.put(1,frist); //1 here is actually the role with user ID 1 permission.put(2,second);//This 2 is the same }
2. Modify controller
Simulate two modules
3. Modify the interceptor
String[] split = requestURL.split("/"); //Intercept the first one. The 0th bit '', 1 is test and 2 is url1 if (split[1] == null) { throw new APIException("url format error"); } String[] strings3 = Constant.permissionResource.get(Integer.valueOf(token)); boolean hasResource = false; for (int i = 0; i < strings3.length; i++) { if (strings3[i].equals(split[1])) { hasResource = true; break; } }
4. Test results
http://localhost:8080/test/url1 token = 2,2 User has test Permission, appear: Congratulations, you have this permission
summary
In fact, using a custom interceptor to do permissions, no matter what type it is, it is basically the same. The most important thing is to deal with it flexibly according to the needs. The above static permissions can be modified by establishing a role table, user table, path table and corresponding relationship. It is easy to configure the dynamic permissions of the URL. The flexible use of custom annotation can be more detailed.