千家信息网

如何使用Spring Boot+Shiro实现权限管理

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要介绍如何使用Spring Boot+Shiro实现权限管理,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一:配置pom.xml文件
千家信息网最后更新 2026年11月02日如何使用Spring Boot+Shiro实现权限管理

这篇文章主要介绍如何使用Spring Boot+Shiro实现权限管理,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

一:配置pom.xml文件

                                    org.apache.shiro                        shiro-spring                        1.4.0                

二:ShiroConfig配置类

@Configurationpublic class ShiroConfig {        @Bean("sessionManager")        public SessionManager sessionManager() {                DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();                sessionManager.setGlobalSessionTimeout(24 * 60 * 60 * 1000);                // 开启会话验证器                sessionManager.setSessionValidationSchedulerEnabled(true);                // 删除失效的session                sessionManager.setDeleteInvalidSessions(true);                // 指定sessionId,使用默认的"JSESSIONID"                sessionManager.setSessionIdCookieEnabled(true);                return sessionManager;        }        /**           * 我们在使用shiro的时候,首先都会先初始化SecurityManager,          * 然后往SecurityManager中注入shiro的其他组件,像sessionManager、realm等。         */        @Bean("securityManager")        public SecurityManager securityManager(OAuth3Realm oAuth3Realm, SessionManager sessionManager) {                DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();                securityManager.setRealm(oAuth3Realm);                securityManager.setSessionManager(sessionManager);                return securityManager;        }        @Bean("shiroFilter")        public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {                ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();                shiroFilter.setSecurityManager(securityManager);                // oauth过滤                Map filters = new HashMap<>();                filters.put("oauth3", new OAuth3Filter());                shiroFilter.setFilters(filters);                // 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行                Map filterMap = new LinkedHashMap<>();                filterMap.put("/webjars/**", "anon");                filterMap.put("/druid/**", "anon");                filterMap.put("/app/**", "anon");                filterMap.put("/file/**", "anon");                filterMap.put("/shiro/login", "anon");                filterMap.put("/swagger/**", "anon");                filterMap.put("/v2/api-docs", "anon");                filterMap.put("/swagger-ui.html", "anon");                filterMap.put("/swagger-resources/**", "anon");                filterMap.put("/captcha.jpg", "anon");                // 其它通过自定义的OAuth3Filter进行过滤                filterMap.put("/**", "oauth3");                shiroFilter.setFilterChainDefinitionMap(filterMap);                return shiroFilter;        }        @Bean("lifecycleBeanPostProcessor")        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {                return new LifecycleBeanPostProcessor();        }        /**          * @Title: defaultAdvisorAutoProxyCreator          * @Description: 扫描上下文,寻找所有的Advistor(通知器),将这些Advisor应用到所有符合切入点的Bean中          * @return   Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。          * @return DefaultAdvisorAutoProxyCreator    返回类型          * @throws          *///      @Bean//      public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {//              DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();//              proxyCreator.setProxyTargetClass(true);//              return proxyCreator;//      }        /**          * @Title: authorizationAttributeSourceAdvisor          * @Description: 开启shiro aop注解支持          * @param securityManager          * @return   参数说明          * @return AuthorizationAttributeSourceAdvisor    返回类型          * @throws          */        @Bean        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {                AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();                advisor.setSecurityManager(securityManager);                return advisor;        }}

其中,如果启用了DefaultAdvisorAutoProxyCreator的话,会导致二次代理的问题,Realm中的doGetAuthorizationInfo会重复调用2次。

三:自定义Shiro Filter类OAuth3Filter

public class OAuth3Filter extends AuthenticatingFilter {    @Override    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {        //获取请求token        String token = getRequestToken((HttpServletRequest) request);        if(StringUtils.isNullOrEmpty(token)){            return null;        }        return new OAuth3Token(token);    }    @Override    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {        //现在vue项目中使用axios发送http请求,每次请求都会多一次Request Method: OPTIONS请求,称为"预检"请求            if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){            return true;        }        return false;    }    @Override    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {        //获取请求token,如果token不存在,直接返回401        String token = getRequestToken((HttpServletRequest) request);        if(StringUtils.isNullOrEmpty(token)){            HttpServletResponse httpResponse = (HttpServletResponse) response;            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");            httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());            String json = new Gson().toJson(R.error(HttpStatus.SC_UNAUTHORIZED, "invalid token"));            httpResponse.getWriter().print(json);            return false;        }        return executeLogin(request, response);    }    @Override    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {        HttpServletResponse httpResponse = (HttpServletResponse) response;        httpResponse.setContentType("application/json;charset=utf-8");        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");        httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());        try {            //处理登录失败的异常            Throwable throwable = e.getCause() == null ? e : e.getCause();            R r = R.error(HttpStatus.SC_UNAUTHORIZED, throwable.getMessage());            String json = new Gson().toJson(r);            httpResponse.getWriter().print(json);        } catch (IOException e1) {        }        return false;    }    /**     * 获取请求的token     */    private String getRequestToken(HttpServletRequest httpRequest){        //从header中获取token        String token = httpRequest.getHeader("token");        //如果header中不存在token,则从参数中获取token        if(StringUtils.isNullOrEmpty(token)){            token = httpRequest.getParameter("token");        }        return "112233445566";//token;    }}

对于复杂的跨域请求,Vue会首先发送一个OPTIONS请求,进行验证。需要后端对所有接口统一处理放行OPTIONS方法(即返回200)即可

四:自定义Token

public class OAuth3Token implements AuthenticationToken {        private String token;        public OAuth3Token(String token) {                this.token = token;        }        /*         * 登录提交的用户名         *          */        @Override        public String getPrincipal() {                return token;        }        /*         * 只被Subject 知道的秘密值,比如我们登录提供的密码         *          */        @Override        public Object getCredentials() {                return token;        }}

五:自定义OAuth3Realm

@Componentpublic class OAuth3Realm extends AuthorizingRealm {        @Autowired        private ShiroService shiroService;        /*         * 判断此Realm是否支持此Token         */        @Override        public boolean supports(AuthenticationToken token) {                return token instanceof OAuth3Token;        }        /*         * 提供用户信息返回权限信息          *          */        @Override        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {                                System.out.println("=============获取已登录用户,权限信息============");                                SysUserEntity user = (SysUserEntity) principals.getPrimaryPrincipal();                Long userId = user.getUserId();                // 用户权限列表                Set permsSet = shiroService.getUserPermissions(userId);                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();                info.setStringPermissions(permsSet);                return info;        }        /*         * 根据token获取认证信息         */        @Override        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {                System.out.println("=============获取已登录用户,用户信息============");                String accessToken = (String) token.getPrincipal();                // 根据accessToken,查询用户信息                SysUserTokenEntity tokenEntity = shiroService.queryByToken(accessToken);                // token失效                if (tokenEntity == null) {                        throw new IncorrectCredentialsException("token失效,请重新登录");                }                // 查询用户信息                SysUserEntity user = shiroService.queryUser(tokenEntity.getUserId());                // 账号锁定                if (user.getStatus().equals("00")) {                        throw new LockedAccountException("账号已被锁定,请联系管理员");                }                SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName() // 返回一个唯一的Realm名字                );                return info;        }}

shiroService用来从数据库或者缓存中,查询用户信息和权限信息。

六:TokenGenerator

public class TokenGenerator {    public static String generateValue() {        return generateValue(UUID.randomUUID().toString());    }    private static final char[] hexCode = "0123456789abcdef".toCharArray();    public static String toHexString(byte[] data) {        if(data == null) {            return null;        }        StringBuilder r = new StringBuilder(data.length*2);        for ( byte b : data) {            r.append(hexCode[(b >> 4) & 0xF]);            r.append(hexCode[(b & 0xF)]);        }        return r.toString();    }    public static String generateValue(String param) {        try {            MessageDigest algorithm = MessageDigest.getInstance("MD5");            algorithm.reset();            algorithm.update(param.getBytes());            byte[] messageDigest = algorithm.digest();            return toHexString(messageDigest);        } catch (Exception e) {           e.printStackTrace();        }        return "";    }}

七:Controller层Demo

@RestController@RequestMapping("shiro")public class ShiroController {        @RequestMapping(value = "/login", method = RequestMethod.GET)        public String login() {                return "login";        }        @RequestMapping(value = "/info", method = RequestMethod.GET)        @RequiresPermissions("sys:config:info")        public String info() {                return "info";        }}

八:登录代码

      @PostMapping("/sys/login")        public Map login(@RequestBody SysLoginForm form)throws IOException {                boolean captcha = captchaService.validate(form.getUuid(), form.getCaptcha());                if(!captcha){                        return R.error("验证码不正确");                }                //用户信息                SysUserEntity user = sysUserService.queryByUserName(form.getUsername());                //账号不存在、密码错误                if(user == null || !user.getPassword().equals(new Sha256Hash(form.getPassword(), user.getSalt()).toHex())) {                        return R.error("账号或密码不正确");                }                //账号锁定                if(Constant.CommonStatus.BANNED.getValue().equals(user.getStatus())){                        return R.error("账号已被锁定,请联系管理员");                }                //生成token,并保存到数据库                R r = sysUserTokenService.createToken(user.getUserId());                return r;        }

登录验证,独立实现,验证成功后创建Token,Token放到Redis缓存中。前端页面请求接口时要带Token.

九:代码调用流程

1.登录成功后,创建Token,后面的接口调用都要传递Token

2.接口首先通过shiroFilter过滤,确定是否要进入OAuth3Filter进行处理

3.OAuth3Filter 首先执行isAccessAllowed方法,如果时OPTIONS请求直接放行,否则进行Shiro的executeLogin验证

4.executeLogin执行的时候会到OAuth3Realm中调用doGetAuthenticationInfo方法,根据Token获取当前登录用户的信息(Token与用户的关联,已在第八点自己实现的登录代码中实现)

5.executeLogin成功后,会看当前访问的接口,有无权限注解@RequiresPermissions

6.如果有注解的话,说需要进行权限验证,Shiro会通过OAuth3Realm的doGetAuthorizationInfo方法,获取当前用户的权限进行验证

以上是"如何使用Spring Boot+Shiro实现权限管理"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

用户 信息 登录 权限 验证 账号 接口 方法 管理 成功 代码 密码 注解 处理 查询 配置 内容 参数 数据 数据库 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技公司简介 上海睿民互联网科技有限公司 互联网和科技技术 奇酷互联网科技 万达互联网科技 顺网科技2021年互联网排名 互联网科技生活的内容 衡水科技产业互联网平台 蓝色互联网科技 银川新华互联网科技职业技术培训学校图片 千方科技属于互联网企业吗 世界互联网领先科技成果获奖 科技互联网的核心竞争力 图游互联网科技 广州智享互联网科技 中国互联网公司的科技投入 北京军民互联网科技公司 互联网对科技影响 承德科技产业互联网平台 小牛互联网科技有限公司地址 华服互联网科技靠谱吗 狮子座互联网科技有限公司 菲比寻常互联网科技 宁夏科技产业互联网案例 青岛科技大学互联网大赛研究生 互联网在线教育科技创业 互联网企业科技类企业如何做账 国产互联网科技公司 东风日产互联网科技公司叫什么 瑞安市蟠桃会互联网科技有限公司
0