Java通過切面實現(xiàn)統(tǒng)一處理Token設(shè)置用戶信息
1. 需求概述
常見的后端開發(fā)中,接口請求中一般前端都是先通過用戶登錄獲取token,每次接口請求都需要在頭信息中攜帶token信息,后端每次都需要手動處理token信息,從token信息中解析獲取用戶信息,因為每個接口都需要處理這些公共信息,所以可以采用切面的方式進(jìn)行統(tǒng)一處理。
2. 解決方案
- 方案一,通過注解+切面處理請求對象 通過切面獲取token信息,然后解析token信息,最后把解析后的token對應(yīng)的用戶信息設(shè)置到請求對象中進(jìn)行統(tǒng)一處理。
- 方案二,通過mybatis攔截器實現(xiàn)動態(tài)sql拼接 實現(xiàn)Interceptor 接口,攔截要執(zhí)行的sql語句。
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),}) public class MybatisLikeSqlInterceptor implements Interceptor {}
3. 代碼實現(xiàn)
3.1 創(chuàng)建解析token
token在線解析:https://www.box3.cn/tools/jwt.html
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.0.M4</version> </dependency>
package com.jerry.market.controller; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.json.JSONUtil; import cn.hutool.jwt.JWT; import cn.hutool.jwt.JWTUtil; import com.jerry.market.entity.AuthorizeTokenInfo; import com.jerry.market.entity.Response; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import java.util.Map; /** * 活動控制器 * * @author zrj * @since 2022-05-05 11:27:01 */ @Slf4j @RestController @RequestMapping("/token") @Api(tags = "TokenController", description = "Token控制器") public class TokenController { private static final String SIGN = "123456"; /** * 創(chuàng)建token */ @PostMapping("/create") @ApiOperation(value = "創(chuàng)建token") public Response<String> createToken(@RequestBody AuthorizeTokenInfo authorizeUserInfo) { if (authorizeUserInfo == null) { authorizeUserInfo = AuthorizeTokenInfo.builder() .userId("Jerry") .userName("小智呀") .tenantId("123456") .createTime(DateUtil.date().toString()) .build(); } Map<String, Object> authorizeUserInfoMap = BeanUtil.beanToMap(authorizeUserInfo); //生成token String token = JWTUtil.createToken(authorizeUserInfoMap, SIGN.getBytes()); log.info("【創(chuàng)建token】創(chuàng)建token成功,token:{}", token); return Response.success("創(chuàng)建token成功", token); } /** * 解析token */ @PostMapping("/parse") @ApiOperation(value = "解析token") public Response<AuthorizeTokenInfo> parseToken(@RequestParam String rightToken) { log.info("【解析token】請求參數(shù),rightToken:{}", rightToken); //驗證簽名 boolean verify = JWTUtil.verify(rightToken, SIGN.getBytes()); if (!verify) { return Response.success("簽名無效,請檢查后重試!", null); } //解析token JWT jwt = JWTUtil.parseToken(rightToken); AuthorizeTokenInfo authorizeUserInfo = JSONUtil.toBean(jwt.getPayloads(), AuthorizeTokenInfo.class); log.info("【解析token】解析token成功,authorizeUserInfo:{}", authorizeUserInfo); return Response.success("解析token成功", authorizeUserInfo); } }
3.2 注解+切面填充參數(shù)
AutoAssemble
package com.jerry.market.config; import java.lang.annotation.*; /** * 自動填充注解 * * @author zrj * @since 2022/5/5 **/ @Documented @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface AutoAssemble { }
AutoAssembleAspect
package com.jerry.market.config; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import cn.hutool.jwt.JWT; import cn.hutool.jwt.JWTUtil; import com.jerry.market.entity.AuthorizeTokenInfo; import com.jerry.market.entity.BaseReqDTO; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; /** * 填充基本信息 * * @author zrj * @since 2022/5/5 **/ @Slf4j @Aspect @Order(99) @Component public class AutoAssembleAspect { // 定義切點位置 private static final String POINT_CUT = "execution(* com.jerry.market.controller..*.*(..))"; private static final String AUTHORIZATION_TOKEN = "authorizationToken"; private static final String SIGN = "123456"; /** * 定義切點位置:下面如果你在SSM中用AOP,在xml中配的就是下面 */ @Pointcut(POINT_CUT) public void pointCut() { } /** * 前置通知 * * @param joinPoint 連接點 * @throws Throwable */ @Before("pointCut()") public void before(JoinPoint joinPoint) throws Throwable { //只處理帶有AutoAssemble注解的控制器 AutoAssemble autoAssemble = joinPoint.getTarget().getClass().getAnnotation(AutoAssemble.class); Object[] args = joinPoint.getArgs(); if (autoAssemble == null || args == null) { log.info("BaseRequestAssembleAspect End Because No AutoAssemble!"); return; } //處理參數(shù) BaseReqDTO baseReqDTO = null; Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); for (Object arg : args) { if (arg instanceof BaseReqDTO) { baseReqDTO = (BaseReqDTO) arg; } } ArgumentsHandler(baseReqDTO, request, method); log.info("BaseRequestAssembleAspect Success!"); } /** * 填充用戶信息 * * @param baseReqDTO 用戶基礎(chǔ)信息 * @param request HttpServletRequest * @param method 方法 * @return void */ private void ArgumentsHandler(BaseReqDTO baseReqDTO, HttpServletRequest request, Method method) { log.info("ArgumentsHandler baseReqDTO:{},request:{},method:{}", baseReqDTO, request, method); if (request != null) { //解析token String rightToken = request.getHeader(AUTHORIZATION_TOKEN); AuthorizeTokenInfo authorizeTokenInfo = parseToken(rightToken); //填充用戶信息 if (authorizeTokenInfo != null) { baseReqDTO.setCreateUid(authorizeTokenInfo.getUserId()); baseReqDTO.setCreateName(authorizeTokenInfo.getUserName()); baseReqDTO.setCreateTime(DateUtil.date()); baseReqDTO.setUpdateUid(authorizeTokenInfo.getUserId()); baseReqDTO.setUpdateName(authorizeTokenInfo.getUserName()); baseReqDTO.setUpdateTime(DateUtil.date()); baseReqDTO.setTenantId(authorizeTokenInfo.getTenantId()); } else { throw new RuntimeException("鑒權(quán)失敗"); } } } /** * 解析token * * @param rightToken token * @return token對象 */ private AuthorizeTokenInfo parseToken(String rightToken) { log.info("parseToken request parameter rightToken:{}", rightToken); if (StrUtil.isEmpty(rightToken)) { log.info("parseToken rightToken is null."); return null; } //驗證簽名 boolean verify = JWTUtil.verify(rightToken, SIGN.getBytes()); if (!verify) { log.info("parseToken verify failed,verify:{}", verify); return null; } //解析token JWT jwt = JWTUtil.parseToken(rightToken); AuthorizeTokenInfo authorizeUserInfo = JSONUtil.toBean(jwt.getPayloads(), AuthorizeTokenInfo.class); log.info("parseToken success,authorizeUserInfo:{}", authorizeUserInfo); return authorizeUserInfo; } }
BaseReqDTO
package com.jerry.market.entity; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.Date; /** * 請求對象基礎(chǔ)類 * * @author zrj * @since 2022/5/5 **/ @Data @NoArgsConstructor @AllArgsConstructor public class BaseReqDTO implements Serializable { private static final long serialVersionUID = 8391616799399185153L; /** * 租戶ID */ private String tenantId; /** * 創(chuàng)建人ID */ private String createUid; /** * 創(chuàng)建人名稱 */ private String createName; /** * 創(chuàng)建時間 */ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; /** * 修改人ID */ private String updateUid; /** * 修改人名稱 */ private String updateName; /** * 修改時間 */ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; }
Activity
package com.jerry.market.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * 活動表(Activity)實體類 * * @author zrj * @since 2022-05-05 11:27:01 */ @Data @NoArgsConstructor @AllArgsConstructor public class Activity extends BaseReqDTO implements Serializable { private static final long serialVersionUID = 774583104822667002L; /** * 主鍵 */ private Long id; /** * 活動編碼 */ private String activityCode; /** * 活動名稱 */ private String activityName; /** * 是否刪除(0:否 1:是) */ private Integer deleted; }
ActivityController
package com.jerry.market.controller; import com.alibaba.fastjson.JSON; import com.jerry.market.config.AutoAssemble; import com.jerry.market.entity.Activity; import com.jerry.market.service.ActivityService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.*; import com.jerry.market.entity.Response; import java.util.List; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; /** * 活動控制器 * * @author zrj * @since 2022-05-05 11:27:01 */ @AutoAssemble @RestController @RequestMapping("/activity") @Api(tags = "ActivityController", description = "活動控制器") public class ActivityController { /** * 服務(wù)對象 */ @Resource private ActivityService activityService; /** * 通過主鍵查詢單條數(shù)據(jù) * * @param activity 參數(shù)對象 * @return 單條數(shù)據(jù) */ @ApiOperation("通過主鍵查詢單條數(shù)據(jù)") @GetMapping("/create") public Response<Activity> get(Activity activity) { System.out.println("用戶基礎(chǔ)信息:" + JSON.toJSONString(activity)); Activity result = activityService.selectById(activity.getId()); if (result != null) { return Response.success("查詢成功", result); } return Response.fail("查詢失敗"); } /** * 新增一條數(shù)據(jù) * * @param activity 實體類 * @return Response對象 */ @ApiOperation("創(chuàng)建活動") @PostMapping("/create") public Response<Activity> create(@RequestBody Activity activity) { int result = activityService.insert(activity); if (result > 0) { return Response.success("新增成功", activity); } return Response.fail("新增失敗"); } /** * 修改一條數(shù)據(jù) * * @param activity 實體類 * @return Response對象 */ @ApiOperation("修改一條數(shù)據(jù)") @PostMapping("/update") public Response<Activity> update(@RequestBody Activity activity) { Activity result = activityService.update(activity); if (result != null) { return Response.success("修改成功", result); } return Response.fail("修改失敗"); } /** * 通過實體作為篩選條件查詢 * * @return Response對象 */ @ApiOperation("通過實體作為篩選條件查詢") @PostMapping("/selectList") public Response<List<Activity>> selectList(Activity activity) { List<Activity> activitys = activityService.selectList(activity); if (activitys != null) { return Response.success("查詢成功", activitys); } return Response.fail("查詢失敗"); } /** * 分頁查詢 * * @param start 偏移 * @param limit 條數(shù) * @return Response對象 */ @ApiOperation("分頁查詢") @PostMapping("/selectPage") public Response<List<Activity>> selectPage(Integer start, Integer limit) { List<Activity> activitys = activityService.selectPage(start, limit); if (activitys != null) { return Response.success("查詢成功", activitys); } return Response.fail("查詢失敗"); } }
4. 測試驗證
到此這篇關(guān)于Java切面統(tǒng)一處理Token設(shè)置用戶信息的文章就介紹到這了,更多相關(guān)Java處理Token設(shè)置用戶信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot和Vue.js實現(xiàn)的前后端分離的用戶權(quán)限管理系統(tǒng)
本文主要介紹了SpringBoot和Vue.js實現(xiàn)的前后端分離的用戶權(quán)限管理系統(tǒng),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04如何使用SpringBoot集成Kafka實現(xiàn)用戶數(shù)據(jù)變更后發(fā)送消息
Spring Boot集成Kafka實現(xiàn)用戶數(shù)據(jù)變更后,向其他廠商發(fā)送消息,我們需要考慮配置Kafka連接、創(chuàng)建Kafka Producer發(fā)送消息、監(jiān)聽用戶數(shù)據(jù)變更事件,并將事件轉(zhuǎn)發(fā)到Kafka,本文分步驟給大家講解使用SpringBoot集成Kafka實現(xiàn)用戶數(shù)據(jù)變更后發(fā)送消息,感興趣的朋友一起看看吧2024-07-07springboot?log4j2日志框架整合與使用過程解析
這篇文章主要介紹了springboot?log4j2日志框架整合與使用,包括引入maven依賴和添加配置文件log4j2-spring.xml的相關(guān)知識,需要的朋友可以參考下2022-05-05計算機二級考試java軟件操作教程 教大家如何學(xué)習(xí)java
如何成為一名知識豐富的Java程序員,順利通過計算機二級Java考試,這篇文章主要主要教大家如何學(xué)習(xí)java,java的學(xué)習(xí)路線是什么,從何學(xué)起,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08Java利用apache ftp工具實現(xiàn)文件上傳下載和刪除功能
這篇文章主要為大家詳細(xì)介紹了Java利用apache ftp工具實現(xiàn)文件上傳下載、刪除功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06