一.导入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 就可以访问 超级管理员列表 这个接口了