Today, I looked at the video of the Dark Horse programmer, a small example of using spring AOP + custom annotations to implement permission control, personally feel that can be used for reference, organized out to share with you.
Requirements: The service tier has methods that require different permissions to access.
Implementation: Customize a privilegeinfo annotation, use this annotation for the service layer of the method to configure the permissions, in the AOP based on the value of the Privilegeinfo annotation, determine whether the user has access to the target method permissions, there is access to the target method, If not, give a hint.
Key Technologies: Custom annotations and annotation parsing, spring AOP
After the final implementation of the directory structure:
Specific steps:
Let's implement this requirement in detail.
To implement this custom annotation first, for the sake of simplicity, the annotation that we are demonstrating simply gives the property of a permission name.
PackagePrivilege.annotation;ImportJava.lang.annotation.ElementType;ImportJava.lang.annotation.Retention;ImportJava.lang.annotation.RetentionPolicy;ImportJava.lang.annotation.Target;/** * Permission annotations * @author minhellic * * * *@Target(Elementtype.method)//This annotation is applied on the method@Retention(Retentionpolicy.runtime) Public@ interface privilegeinfo { /** * The name of the permission * @return * *String value ()default "";}
For this custom annotation, write a parser that is primarily used to return the value of the annotation privilegeinfo setting on the target method
PackagePrivilege.annotation;ImportJava.lang.reflect.Method;/** * Permissions Annotation parser * The main function of this parser is to parse the target method if there are privilegeinfo annotations, then parse out the value of this annotation (the value of the permission) * @author minhellic * */ Public class privilegeannotationparse { /** * Parsing annotations * @param Targetclass class form of the target classes * @param methodName which method is called on the client, MethodName represents which method * @return * @throws Exception * * Public StaticStringParse(Class Targetclass, String methodName)throwsException {String methodaccess ="";/ * * For the sake of simplicity, consider this method without parameters * /method = Targetclass.getmethod (MethodName);//Whether there are privilege annotations on the judging method if(Method.isannotationpresent (Privilegeinfo.class)) {//Get annotations on the methodPrivilegeinfo privilegeinfo = method.getannotation (Privilegeinfo.class); Methodaccess = Privilegeinfo.value (); }returnmethodaccess; }}
With custom annotations and parsers, we write out the corresponding service layer and add this annotation on the way to configure permissions using this annotation. We know that the service layer is made up of interfaces and implementation classes, which is the norm, although it doesn't work for us this time, but we'll keep it in check:
Interface Source code:
PackagePrivilege.service;/** * User Business interface * @author minhellic * */ Public interface firmservice { /** * On target methods that require permissions, use Privilegeinfo annotations to configure permissions for Save * / Public void Save();/** * On target methods that require permissions, use Privilegeinfo annotations to configure permissions for UPDATE * / Public void Update();/** * Do not add privilegeinfo annotations on target methods that do not require permissions * in facets, the default user has permissions */ Public void Get();}
Implementation class Source:
PackagePrivilege.service.impl;ImportPrivilege.annotation.PrivilegeInfo;ImportPrivilege.service.FirmService;/** * User Service Implementation * @author minhellic * */ Public class Firmserviceimpl implements firmservice { /** * On target methods that require permissions, use Privilegeinfo annotations to configure permissions */ @Override @PrivilegeInfo("Save") Public void Save() {System.out.println ("Firmserviceimpl.save ()"); }/** * On target methods that require permissions, use Privilegeinfo annotations to configure permissions */ @Override @PrivilegeInfo("Update") Public void Update() {System.out.println ("Firmserviceimpl.update ()"); }/** * Do not add privilegeinfo annotations on target methods that do not require permissions * in facets, the default user has permissions */ @Override Public void Get() {System.out.println ("Firmserviceimpl.get ()"); }}
To better manage permissions, we've created a permission class that, of course, encapsulates only the name of the permission for simplicity.
PackagePrivilege.userprivilege;/** * Package User rights * is simple, encapsulates only the name of the permission * @author minhellic * */ Public class firmprivilege { /** * Name of user rights * / PrivateString value; PublicStringGetValue() {returnValue } Public void SetValue(String value) { This. value = value; } Public Firmprivilege(String value) { This. value = value; } Public Firmprivilege() { }}
Now that the service layer and annotations are already there, you need to write the code for the slices.
In the aspect, we use the wrapping notice, before calling the target method, we first use the Privilegeinfo annotation on the target method to configure the permissions, and the user has the permissions to match, if the match succeeds, the user has the permission of this target method, then call the target method, otherwise, give the prompt information, The target method is not called.
There is no way to use the front-end notification to match permissions, that is because the pre-notification can also be checked, but regardless of whether the check is passed, the target method will be called, do not have to control the target method calls according to the purpose of permissions.
PackagePrivilege.aspect;ImportJava.util.List;ImportOrg.aspectj.lang.ProceedingJoinPoint;ImportPrivilege.annotation.PrivilegeAnnotationParse;ImportPrivilege.userprivilege.FirmPrivilege;/** * Permission Check slice * Matches the permission configuration of the target method according to the user's original permissions, * If the target method requires permissions that are within the user's original permissions, the calling target method * Does not call the target method if it does not match * @author Minhelli c * * * Public class privilegeaspect { /** * User's own privileges * / PrivateList<firmprivilege> privileges; PublicList<firmprivilege>getprivileges() {returnprivileges; } Public void setprivileges(list<firmprivilege> privileges) { This. privileges = privileges; }/** * Surround notifications in AOP * In this method, check whether the permissions of the user and the target method require a match * if the match calls the target method, the mismatch does not call the * @param joinpoint connection point * @throws throwable * * Public void Isaccessmethod(Proceedingjoinpoint joinpoint)throwsThrowable {/** * 1. Get the access to the target method should have the permissions * to parse the privilegeinfo annotation of the target method, according to our definition of the parser, we need to get: The target class method of class form the name */Class Targetclass = Joinpoint.gettarget (). GetClass (); String methodName = Joinpoint.getsignature (). GetName ();//Get access to this methodString methodaccess = Privilegeannotationparse.parse (Targetclass, methodName);/ * * 2. Traverse the user's permissions to see if they have the appropriate permissions for the target method * / Booleanisaccessed =false; for(Firmprivilege firmprivilege:privileges) {/ * * If the target method does not use Privilegeinfo annotations, the parsed permission string is an empty string * The default user has this permission */ if("". Equals (Methodaccess)) {isaccessed =true; Break; }/* * The permissions in the user's original permission list match the Privilegeinfo annotation configuration on the target method */ if(Firmprivilege.getvalue ()! =NULL&& Firmprivilege.getvalue (). Equalsignorecase (methodaccess)) {isaccessed =true; Break; } }/ * * 3. If the user has permissions, the target method is called, and if not, the target method is not called, only the hint is given */ if(isaccessed) {joinpoint.proceed ();//Call target method}Else{System.out.println ("You don't have permission."); } }}
Finally, to configure the spring configuration file, to use spring AOP, the configuration file must contain an AOP namespace and introduce the appropriate XSD
The source of the configuration file is:
<?xml version= "1.0" encoding= "UTF-8"?><beans xmlns =< Span class= "Hljs-value" > "Http://www.springframework.org/schema/beans" xmlns: AOP = "HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP" xmlns:xsi =" http://www.w3.org/2001/XMLSchema-instance " Span class= "Hljs-attribute" >xsi:schemalocation = "http://www.springframework.org/ Schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd Http://www.springframew ORK.ORG/SCHEMA/AOP http://www.springframework.org/schema/aop/spring-aop-2.5.xsd "; <bean id= "firmservice" class=" Privilege.service.impl.FirmServiceImpl "></Bean> <bean id= "privilegeaspect" class=" Privilege.aspect.PrivilegeAspect "></Bean> <!--configuring facets -- <aop:config> <!--pointcut expression to confirm that the target class Privilege.service.impl all of the classes in the package-- <aop:pointcut expression="Execution (* privilege.service.impl.*.* (..))" id="perform"/> <!--ref points to objects that are tangent-to- <aop:aspect ref="Privilegeaspect"> <!--surround Notifications - <aop:around Method="Isaccessmethod" pointcut-ref="perform"/ > </aop:aspect> </aop:config></Beans>
All the work is done, let's test it out:
PackagePrivilege.test;ImportJava.util.ArrayList;ImportJava.util.List;ImportOrg.junit.Before;ImportOrg.junit.Test;ImportOrg.springframework.context.ApplicationContext;ImportOrg.springframework.context.support.ClassPathXmlApplicationContext;ImportPrivilege.aspect.PrivilegeAspect;ImportPrivilege.service.FirmService;ImportPrivilege.userprivilege.FirmPrivilege;/** * aop+ Annotation Permission Control Test class * * @author minhellic * */ Public class privilegetest { /** * The client calls this service directly, without needing to care about the permissions issue * / PrivateFirmservice Firmservice;/** * In the initialization method, initialize Firmservice * At the same time to give the user the original permissions, this in the project, will be implemented in other ways, here is just simulation, it is not so complicated. @Before Public void Init() {ApplicationContext context =NewClasspathxmlapplicationcontext ("Applicationcontext.xml"); Firmservice = (firmservice) Context.getbean ("Firmservice");/ * * Add default permissions to users * /Privilegeaspect Privilegeaspect = (privilegeaspect) Context.getbean ("Privilegeaspect"); list<firmprivilege> privileges =NewArraylist<firmprivilege> ();//privileges.add (New Firmprivilege ("Save"));Privileges.add (NewFirmprivilege ("Update")); Privilegeaspect.setprivileges (privileges); }/** * The client calls the method in the service directly, without concern for the permissions problem, there will be cut to do * / @Test Public void Test() {firmservice.save (); Firmservice.update (); Firmservice.get (); }}
Run the test method, according to the output of the console, you can see that the permissions control is playing a role, because the user's initial permissions in the Save permission is commented out, the user does not have the Save permission, when calling the Save method, the prompt does not have permissions.
As you can see from the test method above, with AOP, we only need to be concerned with the main business, without needing to be distracted to manage permissions issues.
This blog, although I personally tidy up, but all the ideas and implementation of the way, are from the Dark Horse Programmer's video, is half original it. If the writing sucks, welcome the gods to spray, but please do not insult them.
Spring AOP + custom annotations for a small example of permission control