基于注解实现登录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