<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【Java】若依(ruoyi)——15.操作日志

      查看頁面:https://blog.csdn.net/Felix_hyfy/article/details/105657152

      操作日志

      登錄日志存儲在數(shù)據(jù)表sys_loginfor系統(tǒng)訪問記錄。
      image

      操作日志查看頁:
      image
      那么,操作時,如何寫入日志呢?這時候,涉及到了AOP切面編程。也就是不改變原有方法的基礎(chǔ)上。分離出很多個程序都會涉及到的邏輯。比如:日志記錄、事物管理、安全檢查等。這些邏輯獨立于應(yīng)用程序核心業(yè)務(wù),但又需要應(yīng)用程序去執(zhí)行。此時,我們打開若依的frame子項目,看到子包aspectj下的LogAspect。日志的切面方法。在frame框架中,已引用了aop

      <!-- SpringBoot 攔截器 -->
      <dependency>
      	<groupId>org.springframework.boot</groupId>
      	<artifactId>spring-boot-starter-aop</artifactId>
      </dependency>
      

      image

      在此之前,我們應(yīng)該學(xué)習(xí)AOP
      image

      查看源碼,LogAspect.java 使用@annotation。根據(jù)注解來匹配切點。切點方法如下:

      切點 注解 切點表達式 說明 作用
      boBefore @Before (value = "@annotation(controllerLog)") 處理請求前執(zhí)行 記錄處理請求前的時間
      doAfterReturning @AfterReturning (pointcut = "@annotation(controllerLog)", returning = "jsonResult") 處理完請求后執(zhí)行 寫入正常登錄的日志
      @AfterThrowing @AfterThrowing (value = "@annotation(controllerLog)", throwing = "e") 攔截異常操作 寫入異常操作的日志

      可以看到注解參數(shù)controllerLog,對應(yīng)的注解Log

      /**
       * 自定義操作日志記錄注解
       * 
       * @author ruoyi
       */
      @Target({ ElementType.PARAMETER, ElementType.METHOD })
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface Log
      {
          /**
           * 模塊
           */
          public String title() default "";
      
          /**
           * 功能
           */
          public BusinessType businessType() default BusinessType.OTHER;
      
          /**
           * 操作人類別
           */
          public OperatorType operatorType() default OperatorType.MANAGE;
      
          /**
           * 是否保存請求的參數(shù)
           */
          public boolean isSaveRequestData() default true;
      
          /**
           * 是否保存響應(yīng)的參數(shù)
           */
          public boolean isSaveResponseData() default true;
      
          /**
           * 排除指定的請求參數(shù)
           */
          public String[] excludeParamNames() default {};
      }
      

      那么有哪些方法使用到@Log注釋呢?

      框架 包名 類名 方法名 方法說明
      admin com.*.web.controller.system SysConfigController export 參數(shù)導(dǎo)出管理
      editSave 參數(shù)編輯
      remove 刪除參數(shù)配置
      refreshCache 刷新參數(shù)緩存
      SysDeptController(部門信息) ……
      SysDictDataController(字典數(shù)據(jù)) ……
      SysDictTypeController(數(shù)據(jù)字典信息) ……
      SysMenuController(菜單信息) ……
      SysNoticeController(公告信息) ……
      SysPostController(崗位信息操作處理) ……
      SysProfileController(個人信息業(yè)務(wù)處理) ……
      SysRoleController(角色信息) ……
      SysUserController(用戶管理)

      大體思路:使用切面,處理完成后和異常的切點。(即登錄或異常報錯后,寫入登錄日志)

      在這里,我需要知道AOP以及SpringBoot中如何使用AOP。

      操作日志

      登錄日志存儲在數(shù)據(jù)表sys_loginfor中,表格設(shè)計如下:
      image

      啟動ruoyi,登錄到登錄日志查看頁:
      image

      頁面包含刪除、清空、解鎖、導(dǎo)出、修改功能。登錄日志(系統(tǒng)訪問日志)的代碼與大多數(shù)代碼生成器生成的代碼一起其他頁面類似,這里就不贅述了。

      解鎖:后續(xù)看看怎么回事

      image

      那么,登錄日志如何寫入的呢?應(yīng)該是在登錄接口時寫入。之前我們有學(xué)到若依使用的安全框架——Shiro

      登錄時,調(diào)用認證登錄方法,認證登錄方法調(diào)用域USeRealm.java的認證方法。

      /**
       * 登錄認證
       */
      @Override
      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
      {
      	UsernamePasswordToken upToken = (UsernamePasswordToken) token;
      	String username = upToken.getUsername();
      	String password = "";
      	if (upToken.getPassword() != null)
      	{
      		password = new String(upToken.getPassword());
      	}
      
      	SysUser user = null;
      	try
      	{
      		user = loginService.login(username, password);
      	}
      	catch (CaptchaException e)
      	{
      		throw new AuthenticationException(e.getMessage(), e);
      	}
      	catch (UserNotExistsException e)
      	{
      		throw new UnknownAccountException(e.getMessage(), e);
      	}
      	catch (UserPasswordNotMatchException e)
      	{
      		throw new IncorrectCredentialsException(e.getMessage(), e);
      	}
      	catch (UserPasswordRetryLimitExceedException e)
      	{
      		throw new ExcessiveAttemptsException(e.getMessage(), e);
      	}
      	catch (UserBlockedException e)
      	{
      		throw new LockedAccountException(e.getMessage(), e);
      	}
      	catch (RoleBlockedException e)
      	{
      		throw new LockedAccountException(e.getMessage(), e);
      	}
      	catch (Exception e)
      	{
      		log.info("對用戶[" + username + "]進行登錄驗證..驗證未通過{}", e.getMessage());
      		throw new AuthenticationException(e.getMessage(), e);
      	}
      	SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
      	return info;
      }
      

      授權(quán)時,會執(zhí)行登錄方法: loginService.login(username, password);我們跳轉(zhuǎn)到登錄方法

      /**
       * 登錄
       */
      public SysUser login(String username, String password)
      {
      	// 驗證碼校驗
      	if (ShiroConstants.CAPTCHA_ERROR.equals(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA)))
      	{
      		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
      		throw new CaptchaException();
      	}
      	// 用戶名或密碼為空 錯誤
      	if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
      	{
      		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
      		throw new UserNotExistsException();
      	}
      	// 密碼如果不在指定范圍內(nèi) 錯誤
      	if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
      			|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
      	{
      		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
      		throw new UserPasswordNotMatchException();
      	}
      
      	// 用戶名不在指定范圍內(nèi) 錯誤
      	if (username.length() < UserConstants.USERNAME_MIN_LENGTH
      			|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
      	{
      		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
      		throw new UserPasswordNotMatchException();
      	}
      
      	// IP黑名單校驗
      	String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
      	if (IpUtils.isMatchedIp(blackStr, ShiroUtils.getIp()))
      	{
      		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
      		throw new BlackListException();
      	}
      
      	// 查詢用戶信息
      	SysUser user = userService.selectUserByLoginName(username);
      
      	/**
      	if (user == null && maybeMobilePhoneNumber(username))
      	{
      		user = userService.selectUserByPhoneNumber(username);
      	}
      
      	if (user == null && maybeEmail(username))
      	{
      		user = userService.selectUserByEmail(username);
      	}
      	*/
      
      	if (user == null)
      	{
      		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));
      		throw new UserNotExistsException();
      	}
      	
      	if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
      	{
      		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.delete")));
      		throw new UserDeleteException();
      	}
      	
      	if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
      	{
      		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked")));
      		throw new UserBlockedException();
      	}
      
      	passwordService.validate(user, password);
      
      	AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
      	setRolePermission(user);
      	recordLoginInfo(user.getUserId());      // 記錄登錄信息
      	return user;
      }
      /**
       * 記錄登錄信息
       *
       * @param userId 用戶ID
       */
      public void recordLoginInfo(Long userId)
      {
      	SysUser user = new SysUser();
      	user.setUserId(userId);
      	user.setLoginIp(ShiroUtils.getIp());
      	user.setLoginDate(DateUtils.getNowDate());
      	userService.updateUserInfo(user);
      }
      

      先后進行登錄驗證:(驗證碼校驗;用戶名或密碼為空 錯誤;密碼不在指定范圍內(nèi)錯誤;用戶名不在指定范圍內(nèi)錯誤;IP黑名單校驗;用戶是否存在;用戶已已刪除錯誤;用戶已禁用錯誤;),如果不符合要求,則執(zhí)行異步任務(wù),向前端頁面返回驗證失敗類型;如果符合要求,想前端返回登錄成功信息、設(shè)置角色信息;記錄用戶登錄信息。

      posted @ 2025-06-27 17:13  陸陸無為而治者  閱讀(807)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲欧美国产日韩天堂区| 国产精品自产拍在线播放| 垫江县| 久久精品一区二区三区综合| 四虎永久精品免费视频| 精品久久一线二线三线区| 亚洲精品国模一区二区| 成人亚欧欧美激情在线观看| 东京热加勒比无码少妇| 欧美三级不卡在线观线看高清| 伊人久久大香线蕉综合观| 丰满岳乱妇一区二区三区| 色综合天天色综合久久网| 石泉县| xxxx丰满少妇高潮| 欧美裸体xxxx极品| 巨胸不知火舞露双奶头无遮挡| 91精品乱码一区二区三区| 一区二区三区国产亚洲网站| 亚洲精品国产美女久久久| 亚洲色大成网站www永久一区| 国产精品不卡一区二区久久| 偷拍专区一区二区三区| 免费人成视频在线观看网站| 国产一区二区在线观看粉嫩| 国产免费播放一区二区三区| 国产精品国产三级国av| 宁乡县| 亚洲一区二区偷拍精品| 国产超碰无码最新上传| 国产精品亚洲一区二区三区喷水| 99精品久久毛片a片| 久久香蕉欧美精品| 亚洲日本va午夜中文字幕久久| 留坝县| 不卡一区二区国产精品| 亚洲AV日韩AV激情亚洲 | av色欲无码人妻中文字幕 | 欧美乱妇高清无乱码免费| √天堂中文www官网在线| 亚洲国产成人无码影片在线播放|