Spring中自定义注解支持SpEl表达式(仅限在AOP中使用)

大家平时在写代码的时候,安全方面一般都会考虑使用Shiro或者SpringSecurity,他们其中提供了很多注解可以直接使用,很方便,那么今天就来重复造个小轮子,如果不用他们的,自己在项目中如何基于注解利用SpEl表达式来控制权限呢。下面我们上代码

首先我们定义了一个异常类,代码如下:

public class NoPermissionException extends RuntimeException {

	 /**
	 * 
	 */
	private static final long serialVersionUID = 6262010463678812588L;

	public NoPermissionException() {
	        super();
	    }

	    /** Constructs a new runtime exception with the specified detail message.
	     * The cause is not initialized, and may subsequently be initialized by a
	     * call to {@link #initCause}.
	     *
	     * @param   message   the detail message. The detail message is saved for
	     *          later retrieval by the {@link #getMessage()} method.
	     */
	    public NoPermissionException(String message) {
	        super(message);
	    }

	    /**
	     * Constructs a new runtime exception with the specified detail message and
	     * cause.  <p>Note that the detail message associated with
	     * {@code cause} is <i>not</i> automatically incorporated in
	     * this runtime exception's detail message.
	     *
	     * @param  message the detail message (which is saved for later retrieval
	     *         by the {@link #getMessage()} method).
	     * @param  cause the cause (which is saved for later retrieval by the
	     *         {@link #getCause()} method).  (A <tt>null</tt> value is
	     *         permitted, and indicates that the cause is nonexistent or
	     *         unknown.)
	     * @since  1.4
	     */
	    public NoPermissionException(String message, Throwable cause) {
	        super(message, cause);
	    }
	
}

在看看我们的自定义注解,这个注解直接复制的SpringSecurity中的注解

/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.xzm.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotation for specifying a method access-control expression which will be evaluated to
 * decide whether a method invocation is allowed or not.
 *
 * @author Luke Taylor
 * @since 3.0
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface PreAuthorize {
	/**
	 * @return the Spring-EL expression to be evaluated before invoking the protected
	 * method
	 */
	String value();
}

Controller层的代码如下:

@RequestMapping(value = "/index")
@PreAuthorize("#msg == 'abc'")
public List<User> helloApi(String msg) {
	List<User> users = userMapper.selectList();
	System.out.println(users);
	return users;
}

下面我们来看AOP层面的代码定义

package com.xzm.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import com.xzm.annotations.PreAuthorize;
import com.xzm.exceptions.NoPermissionException;

@Aspect
@Component
public class SpelEnhance {

	/**
	 * 用于SpEL表达式解析.
	 */
	private SpelExpressionParser parser = new SpelExpressionParser();
	/**
	 * 用于获取方法参数定义名字.
	 */
	private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

	@Around("@annotation(com.xzm.annotations.PreAuthorize)")
	public Object around(ProceedingJoinPoint p) throws Throwable {
		MethodSignature sign = (MethodSignature) p.getSignature();
		Method method = sign.getMethod();

		PreAuthorize preAuthorize = method.getAnnotation(PreAuthorize.class);
		if (preAuthorize == null) {
			return p.proceed();
		}

		String value = preAuthorize.value();
		String resV = generateKeyBySpEL(value, p);
		if (resV.equals("true")) {
			return p.proceed();
		}

		throw new NoPermissionException("无权限访问");
	}

	public String generateKeyBySpEL(String spELString, ProceedingJoinPoint joinPoint) {
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
		String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod());
		Expression expression = parser.parseExpression(spELString);
		EvaluationContext context = new StandardEvaluationContext();
		Object[] args = joinPoint.getArgs();
		for (int i = 0; i < args.length; i++) {
			context.setVariable(paramNames[i], args[i]);
		}
		return expression.getValue(context).toString();
	}
}

以上基本上就完了,主要是这段代码
 

public String generateKeyBySpEL(String spELString, ProceedingJoinPoint joinPoint) {
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
		String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod());
		Expression expression = parser.parseExpression(spELString);
		EvaluationContext context = new StandardEvaluationContext();
		Object[] args = joinPoint.getArgs();
		for (int i = 0; i < args.length; i++) {
			context.setVariable(paramNames[i], args[i]);
		}
		return expression.getValue(context).toString();
	}

用来解析SpEl表达式,解析成功后把结果返回。有兴趣的可以在下面评论,技术问题可以私聊我

发布了106 篇原创文章 · 获赞 101 · 访问量 56万+

猜你喜欢

转载自blog.csdn.net/qq_24434671/article/details/101615398