美文网首页
(Java后台)集成shrio—框架引入,代码片段

(Java后台)集成shrio—框架引入,代码片段

作者: 傻傻小萝卜 | 来源:发表于2022-05-09 17:19 被阅读0次

    1.引入shiro

    2.文件夹

    ApplicationContextUtils:用于在shiro中需要集成service,但是由于service还没能加入配置中,比如redisService这样获取用户token的service,可以通过该类加入到spring配置文件applicationContext.xml中

    ShiroCfg:对于shiro的一些配置

    Token:自定义的token,用于shiro中的login方法

    SecurityUtils.getSubject().login(new Token(token));

    TokenFilter:自定义shiro的截取Filter,在shiroCfg中配置自定义filter,根据自定义的规则拦截

    TokenMatcher:自定义matcher,用于shiro进行认证,里边没有多少内容

    TokenRealm:自定义realm,用于认证,添加权限

    ErrorFilter:用于拦截返回的错误,由于shiro中一些抛出的异常,不能使用我们自定义的异常通过Controller抛出,使用该类将shiro抛出的错误转发到定义的ErrorController再抛出

    ErrorController:用于抛出解决shiro抛出的异常,不能按照自定义异常返回

    3.代码片段

    (1)ApplicationContextUtils

    package cn.judouluo.shiro;

    import org.springframework.beans.BeansException;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.ApplicationContextAware;

    import org.springframework.stereotype.Component;

    /**

    * shiro 自定义realm的认证阶段属于filter,当时的spring bean还没有读取进来

    * 需要自己通过方法获取

    */

    @Component

    public class ApplicationContextUtilsimplements ApplicationContextAware {

    private static ApplicationContextcontext =null;

        public static T getBean(Class type) {

    return context.getBean(type);

        }

    @Override

        public void setApplicationContext(ApplicationContext applicationContext)throws BeansException {

            if (ApplicationContextUtils.context ==null) {

            ApplicationContextUtils.context = applicationContext;

            }

    }

    }

    (2)ShiroCfg

    package cn.judouluo.shiro;

    import cn.judouluo.filter.ErrorFilter;

    import org.apache.shiro.realm.Realm;

    import org.apache.shiro.spring.LifecycleBeanPostProcessor;

    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;

    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;

    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;

    import org.springframework.context.annotation.Bean;

    import org.springframework.context.annotation.Configuration;

    import org.springframework.context.annotation.DependsOn;

    import javax.servlet.Filter;

    import java.util.HashMap;

    import java.util.LinkedHashMap;

    import java.util.Map;

    @Configuration

    public class ShiroCfg {

    @Bean

        public Realm realm(){return new TokenRealm(new TokenMatcher());}

    @Bean

        public DefaultWebSecurityManager securityManager(Realm realm){

                return new DefaultWebSecurityManager(realm);

        }

    @Bean

        public ShiroFilterFactoryBean shiroFilterFactoryBean(Realm realm,DefaultWebSecurityManager securityManager){

            ShiroFilterFactoryBean filterBean =new ShiroFilterFactoryBean();

            // 安全管理,添加relam

            filterBean.setSecurityManager(securityManager);

            // 添加自定义Filter

            Map filters =new HashMap<>();

            filters.put("token",new TokenFilter());

            filterBean.setFilters(filters);

            // 设置URL拦截

            Map urlMap =new LinkedHashMap<>();

            // 用户登录

            urlMap.put("/user/login","anon");

            // 将错误的打开

            urlMap.put(ErrorFilter.ERROR_URI,"anon");

            // 其他添加需要token

            urlMap.put("/**","token");

            filterBean.setFilterChainDefinitionMap(urlMap);

            return filterBean;

        }

    /**

    * 解决:@RequiresPermissions导致控制器接口404

    */

        @Bean

        public DefaultAdvisorAutoProxyCreator proxyCreator() {

                DefaultAdvisorAutoProxyCreator proxyCreator =new DefaultAdvisorAutoProxyCreator();

                proxyCreator.setUsePrefix(true);

                return proxyCreator;

        }

    /**

    *  开启shiro aop注解支持.否则@RequiresRoles等注解无法生效

    *  使用代理方式;

        * @param securityManager

        * @return

        */

        @Bean

        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){

            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =new         AuthorizationAttributeSourceAdvisor();

            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);

            return authorizationAttributeSourceAdvisor;

        }

    /**

    * Shiro生命周期处理器

        * @return

        */

        @Bean

        public LifecycleBeanPostProcessor  lifecycleBeanPostProcessor(){

            return new LifecycleBeanPostProcessor();

        }

    /**

    * 自动创建代理

        * @return

        */

        @Bean

        @DependsOn({"lifecycleBeanPostProcessor"})

        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){

            DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator =new                    DefaultAdvisorAutoProxyCreator();

            advisorAutoProxyCreator.setProxyTargetClass(true);

            return advisorAutoProxyCreator;

        }

    }

    (3)Token

    package cn.judouluo.shiro;

    import lombok.Data;

    import org.apache.shiro.authc.AuthenticationToken;

    /**

    * 这个token不是请求时候带的token,只是在shiro中用于验证的时候需要的token

    * 带有username,password

    */

    @Data

    public class Tokenimplements AuthenticationToken {

    private final Stringtoken;

        public Token(String token) {

            this.token = token;

        }

    @Override

        public Object   getPrincipal() {

                return token;

        }

    @Override

        public Object  getCredentials() {

            return token;

        }

    }

    (4)TokenFilter

    package cn.judouluo.shiro;

    import cn.judouluo.pojo.vo.result.CodeMsg;

    import cn.judouluo.redis.service.UserInfoRedisService;

    import cn.judouluo.utils.JsonVos;

    import org.apache.catalina.core.ApplicationContext;

    import org.apache.shiro.SecurityUtils;

    import org.apache.shiro.web.filter.AccessControlFilter;

    import org.springframework.beans.factory.annotation.Autowired;

    import javax.servlet.ServletRequest;

    import javax.servlet.ServletResponse;

    import javax.servlet.http.HttpServletRequest;

    /**

    * 自定义的Filter

    * 用于shiro中使用拦截的类型

    * 表明哪些类型需要使用token进行拦截

    * 作用:验证用户的合法性,是否有相关权限

    */

    public class TokenFilterextends AccessControlFilter {

        public static final StringHEADER_TOKEN ="Token";

        @Autowired

            UserInfoRedisServiceredisService;

        /**

            *当请求被TokenFilter拦截时,就会调用这个函数

            * 可以在这个方法中初步判断   

              * 如果返回true:允许被访问,可以进入下一个链条调用)

                * 比如Filter,拦截器,控制器

                * 如果返回false:不允许访问,会进入onAccessDenied方法,不会进入下一个链条调用

                * 一般都是返回false

                */

        @Override

            protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse     servletResponse, Object o)throws Exception {

                return false;

        }

    /**

    * 当isAccessAllowed返回false时,就会调用这个方法

    * 在这个方法中进行token的校验

    *

    * 如果返回true:允许访问。可以进入下一个链条调用(比如Filter、拦截器、控制器等)

    * 如果返回false:不允许访问。不会进入下一个链条调用(比如Filter、拦截器、控制器等)

    */

        @Override

        protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse)throws Exception {

            HttpServletRequest request = (HttpServletRequest) servletRequest;

            //从header中取出token

            String token = request.getHeader(HEADER_TOKEN);

            // 没有token

            if (token ==null){

                return JsonVos.raise(CodeMsg.NO_TOKEN);

            }

               // token过期

            if (redisService ==null){

                redisService = ApplicationContextUtils.getBean(UserInfoRedisService.class);

            }

                if (redisService.getUserByToken(token) ==null){

                    return JsonVos.raise(CodeMsg.TOKEN_EXPIRED);

            }

                // 鉴权,进入Realm

                // 这里调用token,并不是登录的意思,只是为了触发Realm相应的方法去加载用户的角色,权限信息

                SecurityUtils.getSubject().login(new Token(token));

                   System.out.println("走这里了吗??走走走啊11111"+"TokenFilter");

                    return true;

        }

    }

    (5)TokenMatcher

    package cn.judouluo.shiro;

    import org.apache.shiro.authc.AuthenticationInfo;

    import org.apache.shiro.authc.AuthenticationToken;

    import org.apache.shiro.authc.credential.CredentialsMatcher;

    /**

    * 判断调用login进去是假的判断,这里不需要进行任何操作返回true就可以

    * 证明username和password通过

    */

    public class TokenMatcherimplements CredentialsMatcher {

    @Override

        public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {

    return true;

        }

    }

    (6)TokenRealm

    package cn.judouluo.shiro;

    import cn.judouluo.pojo.dto.SysUserDto;

    import cn.judouluo.pojo.po.SysResource;

    import cn.judouluo.pojo.po.SysRole;

    import cn.judouluo.pojo.po.SysUser;

    import cn.judouluo.redis.service.UserInfoRedisService;

    import org.apache.shiro.authc.AuthenticationException;

    import org.apache.shiro.authc.AuthenticationInfo;

    import org.apache.shiro.authc.AuthenticationToken;

    import org.apache.shiro.authc.SimpleAuthenticationInfo;

    import org.apache.shiro.authz.AuthorizationInfo;

    import org.apache.shiro.authz.SimpleAuthorizationInfo;

    import org.apache.shiro.realm.AuthorizingRealm;

    import org.apache.shiro.subject.PrincipalCollection;

    import org.apache.shiro.util.CollectionUtils;

    import javax.annotation.Resource;

    import java.util.List;

    public class TokenRealm extends AuthorizingRealm {

    @Resource

        UserInfoRedisService redisService;

        public TokenRealm(TokenMatcher tokenMatcher){

            super(tokenMatcher);

        }

    @Override

        public boolean supports(AuthenticationToken token) {

           return tokeninstanceof Token;

        }

    /**

    * 获取权限和角色的

        * @param principalCollection 用户名,这里都是Token

        * @return

        */

        @Override

        protected AuthorizationInfodoGetAuthorizationInfo(PrincipalCollection principalCollection) {

        // 获取当前登录用户的token

            String token = (String)principalCollection.getPrimaryPrincipal();

            // 获取当前用户

            SysUserDto user =redisService.getUserByToken(token);

            SimpleAuthorizationInfo info =new SimpleAuthorizationInfo();

            List roles = user.getRoles();

            if (CollectionUtils.isEmpty(roles))return info;

            // 添加角色

            for (SysRole role : roles) {

                info.addRole(role.getName());

            }

            List resources = user.getResources();

                if (CollectionUtils.isEmpty(resources))return info;

            // 添加权限

            for (SysResource resource : resources) {

                info.addStringPermission(resource.getPermission());

            }

                return info;

        }

    @Override

        protected AuthenticationInfodo GetAuthenticationInfo(AuthenticationToken authenticationToken)throws AuthenticationException {

            String tk = ((Token)authenticationToken).getToken();

          //这里会调用TokenMatcher中的方法

            System.out.println(getName());

            return new SimpleAuthenticationInfo(tk, tk, getName());

        }

    }

    (7)ErrorFilter

    package cn.judouluo.filter;

    import javax.servlet.*;

    import java.io.IOException;

    /**

    * 过滤器

    * 一定要放在最前边,使用try-catch将放在最前边,一旦发生错误将错误的派发给ErrorController

    * 让ErrorController抛出异常,这样就可以使用公共的异常类

    * 这是由于commonExpection 抛出异常需要的是控制器中抛出,如果不在控制器中返回是不可能截取的

    * 所以需要在这个地方将将这个异常通过控制器抛出

    *

    */

    public class ErrorFilterimplements Filter {

        public static final StringERROR_URI ="/handleError";

        @Override

        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,         FilterChain filterChain)throws IOException, ServletException {

                    try {

                            filterChain.doFilter(servletRequest, servletResponse);

                            }catch (Exception e) {

                                servletRequest.setAttribute(ERROR_URI, e);

                    //          // 将错误转派到ERROR_URL,使其控制器抛出异常,

                            // 切记:一定要在ShiroCgf中打开这个错误的url

                            servletRequest.getRequestDispatcher(ERROR_URI).forward(servletRequest,                 servletResponse);

            }

    }

    }

    (8)ErrorController

    package cn.judouluo.controller;

    import cn.judouluo.filter.ErrorFilter;

    import org.springframework.web.bind.annotation.GetMapping;

    import org.springframework.web.bind.annotation.RequestMapping;

    import org.springframework.web.bind.annotation.RestController;

    import javax.servlet.http.HttpServletRequest;

    @RestController

    public class ErrorController {

    @RequestMapping(ErrorFilter.ERROR_URI)

    public void handle(HttpServletRequest request)throws Exception {

    // 抛出异常

            throw (Exception) request.getAttribute(ErrorFilter.ERROR_URI);

        }

    }

    相关文章

      网友评论

          本文标题:(Java后台)集成shrio—框架引入,代码片段

          本文链接:https://www.haomeiwen.com/subject/lxmsertx.html