ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

基于注解实现登录ticket信息解析及验证

2022-05-03 16:03:22  阅读:196  来源: 互联网

标签:return String param auth import 注解 ticket 解析


1、定义方法注解,标识该方法需要解析ticket信息

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;

/**
 * @ClassName:  Auth   
 * @Description:是否验证ticket
 * @author: Ccl
 * @date:   2022年4月29日 上午11:51:54      
 * @Copyright:
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Auth {
    
    boolean isCheck() default true;
}

2、定义切面实现

import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.ccl.order.api.user.entity.UserEntity;
import com.ccl.order.api.user.service.UserService;
import com.ccl.order.auth.ScuserTicket;
import com.ccl.order.conf.exception.AuthFailException;
import com.ccl.order.conf.exception.OperationDeniedException;
import com.ccl.order.redis.enums.RedisKeyEnum;
import com.ccl.order.redis.service.user.UserRedisService;
import com.ccl.order.util.AuthTokenUtils;

/**
 * @ClassName:  AuthAspect   
 * @Description:如果ticket解析错误将不能进入,返回重新登录code,注意,方法的第一个参数必须为ScuserTicket,需要将解析出来的ticket赋值该参数
 * @author: Ccl
 * @date:   2022年5月1日 下午3:07:52      
 * @Copyright:
 */
@Aspect
@Order(value = 2)
@Component
public class AuthAspect {
    
    @Autowired
    public UserService userService;
    @Autowired
    public UserRedisService userRedisService;
    
    //切入点
    @Pointcut(value = "@annotation(com.ccl.order.aop.auth.Auth)")
    private void pointcut() {
    }
    
    @Around(value="pointcut() && @annotation(auth)")
    public Object around(ProceedingJoinPoint joinPoint,Auth auth){
        Object[] args = joinPoint.getArgs(); // 获取目标对象方法参数
        boolean is_auth = auth.isCheck();//是否校验参数
        if(is_auth) {
            String jws = AuthTokenUtils.get_auth_token();//从request中获取ticket
            if (StringUtils.isNotBlank(jws)) {
                //解析ticket获取用户id
                String userId = AuthTokenUtils.get_decode_auth_id(jws);
                //判断ticket缓存是否已经失效
                if(!userRedisService.has(jws)) {
                    throw new AuthFailException("登录信息失效,请重新登录!");
                }
                UserEntity user = userRedisService.get_entity(jws);//从缓存中获取
                if(user == null) {
                    user = userService.getById(userId);//用户信息
                    userRedisService.set(jws, user, RedisKeyEnum.TICKET.getExpire(),TimeUnit.SECONDS);//加入到缓存
                }
                if(user == null){
                    throw new OperationDeniedException("ticket信息错误!");
                }
                ScuserTicket scuserTicket = ScuserTicket.builder().id(userId).companyId(user.getCompanyId()).user(user).build();
                if(args.length > 0) {
                    args[0] = new ScuserTicket();
                    args[0] = scuserTicket;
                }
            }else {
                throw new AuthFailException("ticket格式错误!");
            }
        }
        try {
            return joinPoint.proceed(args);
        } catch (Throwable e) {
            //自定义异常按照正常格式返回
            throw new OperationDeniedException(e.getMessage());
        }
    }
}

3、登录接口,成功后返回ticket信息及将ticket信息放入缓存

@Override
    public Map<String, Object> login_in(UserEntityDTO param) {
        // TODO Auto-generated method stub
        if(StringUtils.isBlank(param.getUserName())) {
            throw new OperationDeniedException("用户名不能为空!");
        }else if(StringUtils.isBlank(param.getUserPassword())) {
            throw new OperationDeniedException("登录密码不能为空!");
        }
        LambdaQueryWrapper<UserEntity> lambdaQueryWrapper = new LambdaQueryWrapper<UserEntity>();
        lambdaQueryWrapper.eq(UserEntity::getUserName, param.getUserName());
        UserEntity userEntity = this.getOne(lambdaQueryWrapper);
        if(userEntity == null) {
            throw new OperationDeniedException("该用户未注册,请先注册!");
        }else {
            String oriPassword = MD5Util.MD5Encode(MD5Util.MD5Encode(param.getUserPassword()));//2次md5加密
            if(!oriPassword.equals(userEntity.getUserPassword())) {//校验密码
                throw new OperationDeniedException("登录密码错误!");
            }
        }
        //生成授权ticket
        String ticket = AuthTokenUtils.generateTicket(userEntity.getId());
        //设置ticket时效
        userRedisService.set(ticket,userEntity,RedisKeyEnum.TICKET.getExpire(),TimeUnit.SECONDS);
        //返回登录信息
        Map<String,Object> retMap = new HashMap<>();
        retMap.put("ticket", ticket);
        retMap.put("userName", userEntity.getUserName());
        return retMap;
    }

4、AuthTokenUtils方法

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;

public class AuthTokenUtils {
    
    private static final String SECRET_KEY = "123455667"; // 严禁修改此变量值
    
    /**
     * @Title: generateTicket   
     * @Description: 生成ticket
     * @param: @param id
     * @param: @return      
     * @return: String      
     * @throws
     */
    public static String generateTicket(String id) {
        Map<String, Object> claims = new HashMap<>();
        String compactJws = Jwts.builder().setSubject(String.valueOf(id)).setId(UUID.randomUUID().toString().replaceAll("-", ""))
                .setIssuedAt(new Date()).addClaims(claims).signWith(SignatureAlgorithm.HS256, SECRET_KEY.getBytes(StandardCharsets.UTF_8)).compact();
        return compactJws;
    }
    
    /**
     * @Title: get_auth_token   
     * @Description: 获取ticket信息
     * @param: @return      
     * @return: String      
     * @throws
     */
    public static String get_auth_token() {
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        String headerAuthorization = request.getHeader("authorization"); // 获取认证数据
        if (StringUtils.isNotBlank(headerAuthorization) && headerAuthorization.startsWith("Bearer")) {
            return headerAuthorization.substring(7);
        }else {
            return "";
        }
    }
    
    /**
     * @Title: get_decode_auth_id   
     * @Description: 解析ticket信息  
     * @param: @param jws
     * @param: @return      
     * @return: String      
     * @throws
     */
    public static String get_decode_auth_id(String jws) {
        Claims clms = null;
        try {
            clms = Jwts.parser().setSigningKey(SECRET_KEY.getBytes(StandardCharsets.UTF_8)).parseClaimsJws(jws).getBody();
        } catch (SignatureException se) {
            try {
                clms = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(jws).getBody();
            } catch (SignatureException se2) {
                return "";
            }
        }
        return clms.getSubject();
    }

}

5、应用

@RestController
@RequestMapping("order")
@Validated
public class OrderController extends BaseController<OrderEntity,OrderService>{
    @Autowired
    private OrderService orderService;

  /**
     * 列表
     */
    @Auth
    @RequestMapping("/list")
    public ApiResponse list(ScuserTicket ticket,OrderEntityDTO param){
        
        return ApiResponse.buildSuccess(orderService.findList(param));
    }
}

6、效果

 

标签:return,String,param,auth,import,注解,ticket,解析
来源: https://www.cnblogs.com/super-ccl/p/16218530.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有