一.導入shiro和jwt的包
<jwt.version>3.4.0</jwt.version>
<shiro.version>1.3.2</shiro.version>
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!-- Shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
二.數據庫表結構
1.用戶表:sys_amdin
2.角色表:sys_role
3.用戶角色中間表:sys_amdin_role
4.權限表:sys_permission
5. 角色權限中間表:sys_role_permission
三.jwt工具類(token加密解密)JwtUtilAdmin
在配置文件里定義三個變量
accessTokenExpireTime=2592000
refreshTokenExpireTime=31104000
shiroCacheExpireTime=31104000
@Component public class JwtUtilAdmin { /** * LOGGER */ private static final Logger LOGGER = LoggerFactory.getLogger(JwtUtilAdmin.class); /** * 過期時間改為從配置文件獲取 */ private static String accessTokenExpireTime; private static Integer shiroCacheExpireTime; /** * JWT認證加密私鑰(Base64加密) */ private static String encryptJWTKey; @Value("${accessTokenExpireTime}") public void setAccessTokenExpireTime(String accessTokenExpireTime) { JwtUtilAdmin.accessTokenExpireTime = accessTokenExpireTime; } @Value("${shiroCacheExpireTime}") public void setShiroCacheExpireTime(Integer shiroCacheExpireTime) { JwtUtilAdmin.shiroCacheExpireTime = shiroCacheExpireTime; } @Value("${encryptJWTKey}") public void setEncryptJWTKey(String encryptJWTKey) { JwtUtilAdmin.encryptJWTKey = encryptJWTKey; } /** * 校驗token是否正確 * * @param token * Token * @return boolean 是否正確 */ public static boolean verify(String token) { try { // 帳號加JWT私鑰解密 String secret = getClaim(token, Constant.ACCOUNT) + Base64.decodeStr(encryptJWTKey, "utf-8"); Algorithm algorithm = Algorithm.HMAC256(secret); JWTVerifier verifier = JWT.require(algorithm)./*acceptExpiresAt(20).*/build(); DecodedJWT jwt = verifier.verify(token); return true; } catch (JWTDecodeException e) { LOGGER.error("JWTToken認證解密出現UnsupportedEncodingException異常:" + e.getMessage()); throw new CustomException("JWTToken認證解密出現UnsupportedEncodingException異常:" + e.getMessage()); } } /** * 獲得Token中的信息無需secret解密也能獲得 * * @param token * @param claim * @return java.lang.String */ public static String getClaim(String token, String claim) { try { DecodedJWT jwt = JWT.decode(token); // 只能輸出String類型,如果是其他類型返回null return jwt.getClaim(claim).asString(); } catch (JWTDecodeException e) { LOGGER.error("解密Token中的公共信息出現JWTDecodeException異常:" + e.getMessage()); throw new CustomException("解密Token中的公共信息出現JWTDecodeException異常:" + e.getMessage()); } } /** * 生成簽名 * * @param account * 帳號 * @return java.lang.String 返回加密的Token * @throws */ public static String sign(String account, String currentTimeMillis) { try { // 帳號加JWT私鑰加密 String secret = account + Base64.decodeStr(encryptJWTKey, "utf-8"); // 此處過期時間是以毫秒為單位,所以乘以1000 Date date = new Date(System.currentTimeMillis() + Long.parseLong(accessTokenExpireTime) * 1000); Algorithm algorithm = Algorithm.HMAC256(secret); // 附帶account帳號信息 return JWT.create().withClaim(Constant.ACCOUNT, account).withClaim(Constant.CURRENT_TIME_MILLIS, currentTimeMillis) .withExpiresAt(date).sign(algorithm); } catch (JWTCreationException e) { LOGGER.error("JWTToken加密出現IllegalArgumentException異常:" + e.getMessage()); throw new CustomException("JWTToken加密出現IllegalArgumentException異常:" + e.getMessage()); } } /** * 生成簽名(業務員,門店賬號) * @param account 帳號 * @return java.lang.String 返回加密的Token */ public static String signOther(String account, String currentTimeMillis) { try { // 帳號加JWT私鑰加密 String secret = account + Base64.decode(encryptJWTKey); // 此處過期時間是以毫秒為單位,所以乘以1000 Date date = new Date(System.currentTimeMillis() + shiroCacheExpireTime *24*60*60*1000l); Algorithm algorithm = Algorithm.HMAC256(secret); // 附帶account帳號信息 return JWT.create().withClaim(Constant.ACCOUNT, account).withClaim(Constant.CURRENT_TIME_MILLIS/*"currentTimeMillis"*/, currentTimeMillis) .withExpiresAt(date).sign(algorithm); } catch (JWTDecodeException e) { LOGGER.error("JWTToken加密出現UnsupportedEncodingException異常:" + e.getMessage()); throw new CustomException("JWTToken加密出現UnsupportedEncodingException異常:" + e.getMessage()); } } }
四.賬號密碼登錄實現類
@Override public BaseResponse<?> loginPassword(String account, String password) { //交於自定義的UserRealm校驗 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(account, password, password); SecurityUtils.getSubject().login(usernamePasswordToken); //登錄成功返回vo SysAdmin admin = new SysAdmin(); admin.setAccount(account); admin.setState(AdminStateEnum.USABLE.getCode()); List<SysAdmin> admins = this.baseMapper.select(admin); admin = admins.get(0); AdminLoginVo adminLoginVo = getAdminLoginVo(admin); adminLoginVo.setAdminId(admin.getId()); if( adminLoginVo.getClinicId() == null){ return BaseResponse.error("診所信息有誤"); } if(!RoleStateEnum.USABLE.getCode().equals(adminLoginVo.getRoleState()) || adminLoginVo.getRoleId() == null){ return BaseResponse.error("角色未啟用"); } //由於http的session不便於測試故舍棄,用security的session Session session = SecurityUtils.getSubject().getSession(); loginSuccess(session, admin.getId(), adminLoginVo); return BaseResponse.success(adminLoginVo); } //登錄成功,將用戶信息存入session,redis並返回 private void loginSuccess(Session session, Integer adminId, AdminLoginVo adminLoginVo){ //登錄用戶ID加密得到token String token = JwtUtilAdmin.sign(adminId.toString(), System.currentTimeMillis() + ""); //登錄成功返回token adminLoginVo.setToken(token); //永久保存 session.setTimeout(-1); session.setAttribute(Constant.CURRENT_USER, adminLoginVo); //以ID為key, 當前時間為value存進redis iRedisService.set(KeyUtil.LOGIN_KEY + token, adminLoginVo, 24 * 60 * 60 * 30 * 36); } //得到登錄返回的AdminLoginVo private AdminLoginVo getAdminLoginVo(SysAdmin admin){ Clinic clinic = iClinicService.selectById(admin.getClinicId()); SysRole sysRole = iSysRoleService.selectByAdminId(admin.getId()); AdminLoginVo adminLoginVo = new AdminLoginVo(admin.getState(), admin.getAuthState()); adminLoginVo.setClinicId(admin.getClinicId()); adminLoginVo.setRoleType(admin.getClinicId()); adminLoginVo.setRoleTypeName(RoleTypeNameUtil.getRoleTypeName(adminLoginVo.getRoleType() , adminLoginVo.getRoleTypeName())); if(clinic != null){ adminLoginVo.setClinicName(clinic.getClinicName()); adminLoginVo.setClinicId(clinic.getId()); } if(sysRole != null){ adminLoginVo.setRoleName(sysRole.getRoleName()); adminLoginVo.setRoleId(sysRole.getId()); adminLoginVo.setRoleState(sysRole.getState()); } return adminLoginVo; }
五.自定義shiroConfig
首先創建JwtFilterAdmin過濾
public class JwtFilterAdmin extends BasicHttpAuthenticationFilter { /** * LOGGER */ private static final Logger LOGGER = LoggerFactory.getLogger(JwtFilterAdmin.class); private IRedisService redisService; { } /** * 這里我們詳細說明下為什么最終返回的都是true,即允許訪問 * 例如我們提供一個地址 GET /article * 登入用戶和游客看到的內容是不同的 * 如果在這里返回了false,請求會被直接攔截,用戶看不到任何東西 * 所以我們在這里返回true,Controller中可以通過 subject.isAuthenticated() 來判斷用戶是否登入 * 如果有些資源只有登入用戶才能訪問,我們只需要在方法上面加上 @RequiresAuthentication 注解即可 * 但是這樣做有一個缺點,就是不能夠對GET,POST等請求進行分別過濾鑒權(因為我們重寫了官方的方法),但實際上對應用影響不大 */ @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { // 查看當前Header中是否攜帶Authorization屬性(Token),有的話就進行登錄認證授權 if (this.isLoginAttempt(request, response)) { try { // 進行Shiro的登錄UserRealm this.executeLogin(request, response); } catch (Exception e) { // 認證出現異常,傳遞錯誤信息msg String msg = e.getMessage(); // 獲取應用異常(該Cause是導致拋出此throwable(異常)的throwable(異常)) Throwable throwable = e.getCause(); if (throwable instanceof SignatureVerificationException) { // 該異常為JWT的AccessToken認證失敗(Token或者密鑰不正確) msg = "Token或者密鑰不正確(" + throwable.getMessage() + ")"; } else if (throwable instanceof TokenExpiredException) { // 該異常為JWT的AccessToken已過期,判斷RefreshToken未過期就進行AccessToken刷新 try{ if (this.refreshToken(request, response)) { return true; } else { msg = "Token已過期(" + throwable.getMessage() + ")"; } }catch(Exception ex){ msg = "Token已過期(" + ex + ")"; } } else { // 應用異常不為空 if (throwable != null) { // 獲取應用異常msg msg = throwable.getMessage(); } } /* 錯誤兩種處理方式 1. 將非法請求轉發到/401的Controller處理,拋出自定義無權訪問異常被全局捕捉再返回Response信息 2. 無需轉發,直接返回Response信息 一般使用第二種(更方便) */ // 直接返回Response信息 this.response401(response, msg); return false; } } else { // 沒有攜帶Token HttpServletRequest httpServletRequest = WebUtils.toHttp(request); // 獲取當前請求類型 String httpMethod = httpServletRequest.getMethod(); // 獲取當前請求URI String requestURI = httpServletRequest.getRequestURI(); LOGGER.info("當前請求 {} Authorization屬性(Token)為空 請求類型 {}", requestURI, httpMethod); // mustLoginFlag = true 開啟任何請求必須登錄才可訪問 Boolean mustLoginFlag = false; //開啟h5頁面不能訪問? if (mustLoginFlag) { this.response401(response, "請先登錄"); return false; } } return true; } /** * 這里我們詳細說明下為什么重寫 * 可以對比父類方法,只是將executeLogin方法調用去除了 * 如果沒有去除將會循環調用doGetAuthenticationInfo方法 */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { this.sendChallenge(request, response); return false; } /** * 檢測Header里面是否包含Authorization字段,有就進行Token登錄認證授權 */ @Override protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) { // 拿到當前Header中Authorization的AccessToken(Shiro中getAuthzHeader方法已經實現) //String token = this.getAuthzHeader(request); String token = WebUtils.toHttp(request).getHeader("token"); return StringUtils.isNotBlank(token); } /** * 進行AccessToken登錄認證授權 */ @Override protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { String tokenStr = WebUtils.toHttp(request).getHeader("token"); LOGGER.info("獲得header里的token= {}", tokenStr); JwtTokenAdmin token = new JwtTokenAdmin(tokenStr); // 提交給UserRealm進行認證,如果錯誤他會拋出異常並被捕獲 this.getSubject(request, response).login(token); // 如果沒有拋出異常則代表登入成功,返回true return true; } /** * 對跨域提供支持 */ @Override protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = WebUtils.toHttp(request); HttpServletResponse httpServletResponse = WebUtils.toHttp(response); httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin")); httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE"); httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers")); // 跨域時會首先發送一個OPTIONS請求,這里我們給OPTIONS請求直接返回正常狀態 if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { httpServletResponse.setStatus(HttpStatus.OK.value()); return false; } return super.preHandle(request, response); } /** * 此處為AccessToken刷新,進行判斷RefreshToken是否過期,未過期就返回新的AccessToken且繼續正常訪問 */ private boolean refreshToken(ServletRequest request, ServletResponse response) { String token = WebUtils.toHttp(request).getHeader("token"); // 獲取當前Token的帳號信息 String account = JwtUtilAdmin.getClaim(token, Constant.ACCOUNT); Map<String, String> oldTokenMap = redisService.hmget(Constant.PREFIX_SHIRO_REFRESH_TOKEN + account); String refreshExpireTime = oldTokenMap.get(token); if (refreshExpireTime != null) { String key = KeyUtil.keyOf(KeyUtil.TRY_LOCK, account); try{ if(redisService.tryLock(key)){ //控制異步並發請求 String newToken = refreshToken(account); if(newToken == null) { return false; } JwtTokenAdmin jwtTokenAdmin = new JwtTokenAdmin(newToken); this.getSubject(request, response).login(jwtTokenAdmin); LOGGER.info("舊的token={}被新token{}替換", token, newToken); return true; } }finally{ redisService.remove(key); } } return true; } /** * token 過期 才能用 * @param id */ public String refreshToken(String id){ //過期token String old = Constant.PREFIX_SHIRO_OLD_TOKEN + id; //當前token String current = Constant.PREFIX_SHIRO_REFRESH_TOKEN + id; Map<String, String> map = null; if(redisService.exsits(old)) { //當前token已過期,並且token已刷新, 返回刷新過的新token map = redisService.hmget(Constant.PREFIX_SHIRO_REFRESH_TOKEN + id); for(String token : map.keySet()) { return token; } return null; }else { //刷新token String currentTimeMillis = String.valueOf(System.currentTimeMillis()); String token = JwtUtilAdmin.sign(id, currentTimeMillis); //accessExpireTime try{ map = redisService.hmget(Constant.PREFIX_SHIRO_REFRESH_TOKEN + id); map.put(token, currentTimeMillis); }catch(Exception e){ map = Maps.newHashMap(); map.put(token, currentTimeMillis); } //30天 超時時間 String refreshTokenExpireTime = SpringContextUtil.getEnvironmentProperty("refreshTokenExpireTime"); redisService.hmset(Constant.PREFIX_SHIRO_REFRESH_TOKEN + id, map, Integer.parseInt(refreshTokenExpireTime)); return token; } } /** * 無需轉發,直接返回Response信息 */ private void response401(ServletResponse response, String msg) { LOGGER.info("3" + Thread.currentThread().getName()); HttpServletResponse httpServletResponse = WebUtils.toHttp(response); httpServletResponse.setStatus(HttpStatus.OK.value()); httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.setContentType("application/json; charset=utf-8"); try (PrintWriter out = httpServletResponse.getWriter()) { Map<Integer, String> result = Maps.newHashMap(); result.put(401, "無權訪問,請重新登錄"); String data = JSON.toJSONString(result); out.append(data); } catch (IOException e) { LOGGER.error("直接返回Response信息出現IOException異常:" + e.getMessage()); throw new CustomException("直接返回Response信息出現IOException異常:" + e.getMessage()); } } private void setResponseheader(String token, ServletResponse response){ // 最后將刷新的AccessToken存放在Response的Header中的Authorization字段返回 HttpServletResponse httpServletResponse = WebUtils.toHttp(response); httpServletResponse.setHeader("Authorization", token); httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization"); } }
在shiroConfig里調用我們創建的jwt攔截規則
@Configuration public class ShiroConfig { /** * 配置使用自定義Realm,關閉Shiro自帶的session 詳情見文檔 * http://shiro.apache.org/session-management.html#SessionManagement- * StatelessApplications%28Sessionless%29 * * @param userRealm */ @Bean("securityManager") public DefaultWebSecurityManager defaultWebSecurityManager(MyRealmAdmin userRealm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); // 使用自定義Realm defaultWebSecurityManager.setRealm(userRealm); // 關閉Shiro自帶的session DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); defaultSessionStorageEvaluator.setSessionStorageEnabled(false); subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); defaultWebSecurityManager.setSubjectDAO(subjectDAO); // 設置自定義Cache緩存 defaultWebSecurityManager.setCacheManager(new CustomCacheManager()); return defaultWebSecurityManager; } @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); // 添加自己的過濾器取名為jwt Map<String, Filter> filterMap = new HashMap<>(16); filterMap.put("jwt", new JwtFilterAdmin()); factoryBean.setFilters(filterMap); factoryBean.setSecurityManager(securityManager); /** * anon:無需認證 * authc:必須認證 * user:如果使用rememberMe可直接訪問 * perms:該資源必須得到資源權限才可以訪問 * role:該資源必須得到資源權限才可以訪問 */ // 自定義url規則使用LinkedHashMap有序Map LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(16); //登錄 filterChainDefinitionMap.put("/login/*", "anon"); //獲取驗證碼 filterChainDefinitionMap.put("/phone/code", "anon"); //獲取角色類型 filterChainDefinitionMap.put("/role/type", "anon"); //無權限異常 filterChainDefinitionMap.put("/exception/getException", "anon"); //上傳圖片/文件 filterChainDefinitionMap.put("/img/getUrl", "anon"); //jwt攔截 filterChainDefinitionMap.put("/**", "jwt"); factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return factoryBean; } /** * 下面的代碼是添加注解支持 */ @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); // 強制使用cglib,防止重復代理和可能引起代理出錯的問題,https://zhuanlan.zhihu.com/p/29161098 defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; }
@Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); }
@Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } }
六.自定義userRealm
public abstract class MyRealmAdmin extends AuthorizingRealm { }
@Service public class UserRealm extends MyRealmAdmin { @Autowired private IRedisService iRedisService; @Autowired private ISysAdminService iSysAdminService; @Autowired private ISysRoleService iSysRoleService; @Autowired private ISysPermissionService iSysPermissionService; @Autowired private IClinicService iClinicService; @Override public boolean supports(AuthenticationToken authenticationToken) { return authenticationToken instanceof JwtTokenAdmin || authenticationToken instanceof UsernamePasswordToken; } /** * 只有當需要檢測用戶權限的時候才會調用此方法,例如checkRole,checkPermission之類的 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); String account = JwtUtilAdmin.getClaim(principalCollection.toString(), Constant.ACCOUNT); SysAdmin userDto = new SysAdmin(); userDto.setId(Integer.valueOf(account)); // 查詢用戶角色 SysRole roleDto = iSysRoleService.selectByAdminId(Integer.valueOf(account)); if (roleDto != null) { // 根據用戶角色查詢權限 List<SysPermission> permissionDtos = iSysPermissionService.selectByRoleId(roleDto.getId()); for (SysPermission permissionDto : permissionDtos) { if (permissionDto != null && StringUtils.isNotBlank(permissionDto.getPermissionStr())) { // 添加權限 simpleAuthorizationInfo.addStringPermission(permissionDto.getPermissionStr()); } } } return simpleAuthorizationInfo; } /** * 默認使用此方法進行用戶名正確與否驗證,錯誤拋出異常即可。 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { if(authenticationToken instanceof UsernamePasswordToken){ UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken; String account = token.getUsername(); String password = token.getHost(); //賬號密碼登錄校驗 SysAdmin admin = new SysAdmin(); admin.setAccount(account); admin.setState(AdminStateEnum.USABLE.getCode()); List<SysAdmin> admins = iSysAdminService.select(admin); if(admins.size() == 0){ throw new AuthenticationException("賬號不存在"); } if(admins.size() > 1){ throw new AuthenticationException("賬號信息有誤"); } admin = admins.get(0); if(!admin.getPassword().equals(MD5Util.MD5SaltEncodeing(password))){ throw new AuthenticationException("密碼錯誤,請重新填寫"); } if(!AdminAuthStateEnum.PASS.getCode().equals(admin.getAuthState())){ throw new AuthenticationException(AdminAuthStateEnum.valueOfCode(admin.getAuthState()).getMessage()); } return new SimpleAuthenticationInfo(token, password, account); }else { //調用其它接口時token校驗 Object credential = authenticationToken.getCredentials(); if(credential == null){ throw new AuthenticationException("Token為空(The Token is empty.)"); } String token = credential.toString(); // 解密獲得account,用於和數據庫進行對比 if (JwtUtilAdmin.verify(token)) { String account = JwtUtilAdmin.getClaim(token, Constant.ACCOUNT); if (StringUtil.isBlank(account)) { throw new AuthenticationException("Token中帳號為空(The account in Token is empty.)"); } AdminLoginVo adminLoginVo = iRedisService.get(KeyUtil.LOGIN_KEY + token, AdminLoginVo.class); if (adminLoginVo != null) { SysAdmin sysAdmin = iSysAdminService.selectById(Integer.valueOf(account)); if (sysAdmin == null) { throw new AuthenticationException("該帳號不存在(The account does not exist.)"); } if(!RoleTypeEnum.USABLE.getCode().equals(adminLoginVo.getRoleType())){ Clinic clinic = iClinicService.selectById(sysAdmin.getClinicId()); if(!Constant.ZERO.equals(clinic.getState())) { switch (clinic.getState()) { case 10: throw new AuthenticationException("該診所已被禁用"); case 20: throw new AuthenticationException("該診所正在審核中"); case 30: throw new AuthenticationException("該診所審核失敗"); default: break; } } } return new SimpleAuthenticationInfo(token, token, account); } } throw new AuthenticationException("Token已過期(Token expired or incorrect.)"); } } }
七.JwtTokenAdmin
public class JwtTokenAdmin implements AuthenticationToken { private static final long serialVersionUID = 960867003694917627L; /** * Token */ private String token; public JwtTokenAdmin(String token) { this.token = token; } @Override public Object getPrincipal() { return token; } @Override public Object getCredentials() { return token; } }
八.關於授權
在接口上加入注解, 引號內為菜單標識, 需存入權限表sys_permission 的permission_str字段里
@RequiresPermissions("super:admin:list")
sys_permission:
sys_role_permission:
sys_role:
sys_admin_role:
sys_admin:
接口代碼:
/** * @description: //:超級管理員列表 * @auth onfec * @param keyWord 根據賬號, 姓名, 手機號模糊查詢 * @return com.sysf.doc.BaseResponse<?> * @date 2020/7/7 11:48 */ @RequiresPermissions("super:admin:list") @RequestMapping("list") public BaseResponse<?> superList(String keyWord, Integer state, String startTime, String endTime, @RequestParam(value = "pageNum", defaultValue = "0") Integer pageNum, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize){ keyWord = NullUtil.getStringNull(keyWord); state = NullUtil.getIntegerNull(state); startTime = NullUtil.getStringNull(startTime); endTime = NullUtil.getStringNull(endTime); return iSysAdminService.superList(keyWord, state, startTime, endTime, pageNum, pageSize); }
這樣我們的用戶: admin 就可以訪問 超級管理員列表 這個接口了