Spring AOP自定义注解 身份验证

最近碰到APP开发权限验证的问题 用过滤器不能解决某些无需验证的方法 所以最终选择用AOP 解决

代码如下定义一个权限注解

package com.thinkgem.jeesite.common.annotation;

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

/**
 * 权限注解
 * Created by Hamming on 2016/12/26.
 */
@Target(ElementType.METHOD)//这个注解是应用在方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessToken {
/*    String userId();
    String token();*/
}
获取页面请求中的ID token

@Aspect
@Component
public class AccessTokenAspect {

    @Autowired
    private ApiService apiService;

    @Around("@annotation(com.thinkgem.jeesite.common.annotation.AccessToken)")
    public Object doAccessCheck(ProceedingJoinPoint pjp) throws Throwable{
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String id = request.getParameter("id");
        String token = request.getParameter("token");
        boolean verify = apiService.verifyToken(id,token);
        if(verify){
            Object object = pjp.proceed(); //执行连接点方法
            //获取执行方法的参数

            return object;
        }else {
            return ResultApp.error(3,"token失效");
        }
    }
}

token验证类  存储用到redis

package com.thinkgem.jeesite.common.service;

import com.thinkgem.jeesite.common.utils.JedisUtils;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.crypto.MacProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import java.io.*;
import java.security.Key;
import java.util.Date;

/**
 *token登陆验证
 * Created by Hamming on 2016/12/23.
 */
@Service
public class ApiService {
    private static final String at="accessToken";

    public static Key key;

//    private Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * 生成token
     * Key以字节流形式存入redis
     *
     * @param date  失效时间
     * @param appId AppId
     * @return
     */
    public String generateToken(Date date, String appId){
        Jedis jedis = null;
        try {
            jedis = JedisUtils.getResource();
            byte[] buf = jedis.get("api:key".getBytes());
            if (buf == null) { // 建新的key
                key = MacProvider.generateKey();
                ByteArrayOutputStream bao = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(bao);
                oos.writeObject(key);
                buf = bao.toByteArray();
                jedis.set("api:key".getBytes(), buf);
            } else { // 重用老key
                key = (Key) new ObjectInputStream(new ByteArrayInputStream(buf)).readObject();
            }

        }catch (IOException io){
//            System.out.println(io);
        }catch (ClassNotFoundException c){
//            System.out.println(c);
        }catch (Exception e) {
//            logger.error("ApiService", "generateToken", key, e);
        } finally {
            JedisUtils.returnResource(jedis);
        }

        String token = Jwts.builder()
                .setSubject(appId)
                .signWith(SignatureAlgorithm.HS512, key)
                .setExpiration(date)
                .compact();
        // 计算失效秒,7889400秒三个月
        Date temp = new Date();
        long interval = (date.getTime() - temp.getTime())/1000;
        JedisUtils.set(at+appId ,token,(int)interval);
        return token;
    }

    /**
     * 验证token
     * @param appId AppId
     * @param token token
     * @return
     */
    public boolean verifyToken(String appId, String token) {
        if( appId == null|| token == null){
            return false;
        }
        Jedis jedis = null;
        try {
            jedis = JedisUtils.getResource();
            if (key == null) {
                byte[] buf = jedis.get("api:key".getBytes());
                if(buf==null){
                    return false;
                }
                key = (Key) new ObjectInputStream(new ByteArrayInputStream(buf)).readObject();
            }
            Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody().getSubject().equals(appId);
            return true;
        } catch (Exception e) {
//            logger.error("ApiService", "verifyToken", key, e);
            return false;
        } finally {
            JedisUtils.returnResource(jedis);
        }
    }

    /**
     * 获取token
     * @param appId
     * @return
     */
    public String getToken(String appId) {
        Jedis jedis = null;
        try {
            jedis = JedisUtils.getResource();
            return jedis.get(at+appId);
        } catch (Exception e) {
//            logger.error("ApiService", "getToken", e);
            return "";
        } finally {
            JedisUtils.returnResource(jedis);
        }
    }
}

spring aop配置 
    <!--aop -->
    <!--      扫描注解bean -->
    <context:component-scan base-package="com.thinkgem.jeesite.common.aspect"/>
    <aop:aspectj-autoproxy proxy-target-class="true"/>


验证权限方法使用 直接用注解就可以了AccessToken

例如

package com.thinkgem.jeesite.modules.app.web.pay;

import com.alibaba.fastjson.JSON;
import com.thinkgem.jeesite.common.annotation.AccessToken;
import com.thinkgem.jeesite.common.base.ResultApp;
import com.thinkgem.jeesite.modules.app.service.pay.AppAlipayConfService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

/**
 * 支付接口
 * Created by Hamming on 2016/12/27.
 */
@Controller
@RequestMapping(value = "/app/pay")
public class AppPayModule {

    @Autowired
    private AppAlipayConfService appAlipayConfService;

    @RequestMapping(value = "/alipay", method = RequestMethod.POST, produces="application/json")
    @AccessToken
    @ResponseBody
    public Object alipay(String orderId){
        if(orderId ==null){
            Map re = new HashMap<>();
            re.put("result",3);
            re.put("msg","参数错误");
            String json = JSON.toJSONString(re);
            return json;
        }else {
            return null;
        }
    }
}


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring AOP(面向切面编程)是Spring框架中的一个关键特性,它允许开发者在不修改原始代码的情况下,通过切入点和通知来实现横切关注点的功能。 下面我给出一个简单的Spring AOP的例子来解释其工作原理。 假设我们有一个Spring应用程序,其中包含一个名为UserService的服务类,负责处理用户相关的业务逻辑,比如验证用户、保存用户等操作。 首先,我们需要定义一个切入点(Join point),用来确定在UserService的哪些方法上我们需要应用AOP。例如,我们可以将切入点定义为所有保存用户的方法。 其次,我们需要定义通知(Advice),它是在切入点之前或之后执行的代码逻辑。例如,我们可以定义一个前置通知(Before advice)来在保存用户之前验证用户的信息。 接下来,我们需要将切入点和通知组合起来,创建一个切面(Aspect)。切面是一个类,它包含了切入点和通知,并指定了在切入点上何时应用通知。在我们的例子中,切面可以是一个名为ValidationAspect的类,其中定义了一个前置通知方法。 最后,我们需要将切面配置为Spring容器的一部分。我们可以通过在Spring的配置文件中声明一个<aop:aspectj-autoproxy>元素来完成这一配置。这样,当应用程序启动时,Spring容器会自动为我们创建切面。 当我们调用UserService的保存用户方法时,Spring AOP就会根据切面配置来决定是否将前置通知应用于该方法。如果切入点的条件匹配,前置通知会提前执行验证用户的逻辑。 通过这个例子,我们可以看到,Spring AOP提供了一种非侵入式的方式来增强代码的功能,使得我们可以在不修改原始代码的情况下,通过切入点和通知来实现横切关注点的功能。这样可以提高代码的模块化和可重用性,降低代码的复杂性。 ### 回答2: Spring AOP(面向切面编程)是Spring框架中的一个重要特性,用于在不改变原有代码的情况下增加功能和耦合性。它通过将主要的业务逻辑(核心业务)与横切关注点(如日志记录、事务管理等)分离来实现。 下面是一个可以帮助理解Spring AOP的例子:假设我们有一个简单的应用程序,其中包含一个Service层的类来处理用户的注册请求。在用户注册成功后,我们希望自动生成一个欢迎邮件,同时在控制台中记录下来。这里就可以使用Spring AOP来实现。 首先,我们需要定义一个切面类来处理横切关注点,例如记录日志和发送欢迎邮件。切面类应该实现通知(Advice)。在这个例子中,我们可以使用@Before通知来在目标方法执行之前发送欢迎邮件,并使用@After通知在目标方法执行之后记录日志。 接下来,在Spring配置文件中进行配置。我们需要定义一个切点(Pointcut),以告诉Spring在哪些方法上应用切面。在这个例子中,我们可以使用execution()表达式定义一个切点,以匹配Service层中的所有方法。 最后,在Service层的类中,我们需要使用一个@Autowired注解将切面类注入到目标类中。这样,当Service层中的方法被调用时,切面类就会自动执行。 通过这个例子,我们可以清楚地看到Spring AOP如何帮助我们将横切关注点与核心业务分离,并在不改变原有代码的情况下实现功能的增强。这样,我们可以更容易地维护、扩展和重用代码,提高系统的可维护性和灵活性。 ### 回答3: Spring AOPSpring框架中的一个关键特性,它提供了一种方法来通过动态代理技术在应用程序的不同层之间添加横切关注点。 举一个简单的例子来说明Spring AOP的用法。假设我们有一个电商网站,我们想要在用户购买商品之前验证用户的身份。我们可以通过使用Spring AOP来实现这个功能。 首先,我们需要定义一个切面(Aspect),用于对购买商品的方法进行拦截和处理。我们可以创建一个类,并在其中定义一个方法,使用@Before注解来标记它。在这个方法中,我们可以编写代码来验证用户的身份,例如检查用户是否已登录。 然后,我们需要配置Spring AOP,告诉它在哪些类和方法上应用这个切面。我们可以在Spring配置文件中使用<aop:aspectj-autoproxy>元素来启用自动代理,然后在<aop:config>元素中定义切面的位置和应用规则。 接下来,我们需要在我们的购买商品方法上添加一个标记(Annotation),以告诉Spring AOP对该方法应用切面。我们可以在方法上添加一个自定义的注解,例如@RequiresAuthentication。然后,我们可以在切面的方法中使用@Pointcut注解来指定切入点,即哪些方法应该被拦截。 最后,我们可以测试这个例子。我们可以创建一个控制器(Controller),其中有一个方法用于购买商品。当用户调用该方法时,Spring AOP会自动拦截并执行切面中的逻辑,验证用户的身份是否合法。如果用户未登录或身份验证失败,可以抛出异常或返回错误信息。 综上所述,Spring AOP是一个非常强大的功能,可以帮助我们在应用程序中实现横切关注点,提高代码的模块化和可维护性。以上是一个简单的例子,展示了如何使用Spring AOP来验证用户身份。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值