springboot集成shiro

作者: 小尘哥 | 来源:发表于2018-04-28 15:35 被阅读56次

    废话少说,先简单说下怎么用,至于shiro是什么,请移步shiro官网

    1、添加依赖

                <dependency>
                    <groupId>org.apache.shiro</groupId>
                    <artifactId>shiro-core</artifactId>
                    <version>${shiro.version}</version>
                </dependency>
    
                <dependency>
                    <groupId>org.apache.shiro</groupId>
                    <artifactId>shiro-web</artifactId>
                    <version>${shiro.version}</version>
                </dependency>
    
                <dependency>
                    <groupId>org.apache.shiro</groupId>
                    <artifactId>shiro-spring</artifactId>
                    <version>${shiro.version}</version>
                </dependency>
    
                <dependency>
                    <groupId>net.mingsoft</groupId>
                    <artifactId>shiro-freemarker-tags</artifactId>
                    <version>${shiro-freemarker.version}</version>
                </dependency>
    

    2、重写AuthorizingRealm

    AuthorizingRealm主要包括两个方法:doGetAuthorizationInfo(PrincipalCollection principals)和doGetAuthenticationInfo(AuthenticationToken token)
    1.doGetAuthenticationInfo(AuthenticationToken token)在登录认证时候被调用,即SecurityUtils.getSubject().login()执行时候被调用
    2.doGetAuthorizationInfo(PrincipalCollection principals)获取权限认证信息,即SecurityUtils.getSubject().isPermitted()执行时候被调用
    我这里定义成abstract 是为了提取该类为公用,其他项目可以复用集成。

    public abstract class AbstarctAuthorizingRealm extends AuthorizingRealm {
    
        @Resource
        private IUserService userService;
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            Object primaryPrincipal = principals.getPrimaryPrincipal();
            if (primaryPrincipal == null) {
                return null;
            }
    
            IUser user = (IUser) primaryPrincipal;
    
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.setStringPermissions(findPermissions(user));
            info.setRoles(findRoles(user));
    
            return info;
        }
    
      
          /**
          * 获取用户的权限集合
          */
        protected abstract Set<String> findPermissions(IUser user);
        /**
          * 获取用户的角色集合
          */
        protected abstract Set<String> findRoles(IUser user);
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            UsernamePasswordToken upt = (UsernamePasswordToken) token;
            String username = upt.getUsername();
            char[] password = upt.getPassword();
            if (StringUtils.isBlank(username)) {
                throw new MustUsernameException();
            }
    
            if (password == null || password.length == 0) {
                throw new MustPasswordException();
            }
    
            IUser user = userService.findUserByUsername(username);
            if (user == null) {
                throw new UnknownAccountException();
            }
    
            if (Boolean.TRUE.equals(user.getLocked())) {
                throw new LockedAccountException();
            }
    
            if (Boolean.TRUE.equals(user.getDisabled())) {
                throw new DisabledAccountException();
            }
    
            AuthenticationInfo authenticationInfo = assertAuthenticationInfo(user);
    
            return authenticationInfo;
        }
    
        protected AuthenticationInfo assertAuthenticationInfo(IUser user) {
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
            return authenticationInfo;
        }
    
        protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)
                throws AuthenticationException {
            CredentialsMatcher cm = getCredentialsMatcher();
            if (cm != null) {
                if (!cm.doCredentialsMatch(token, info)) {
                    throw new IncorrectCredentialsException();
                }
            } else {
                throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify "
                        + "credentials during authentication.  If you do not wish for credentials to be examined, you "
                        + "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
            }
        }
    
        public IUserService getUserService() {
            return userService;
        }
    
        public void setUserService(IUserService userService) {
            this.userService = userService;
        }
    

    IUser也是一个接口,包括用户基本登录信息,方便每个用到的项目自己做实现

    public interface IUser {
    
        String getUsername();
    
        String getPassword();
    
        Boolean getDisabled();
    
        Integer getDeleted();
    
        Boolean getLocked();
    
    }
    

    3、登录成功回调(重写FormAuthenticationFilter)

    比如登录成功后需要修改用户最后登录时间,登录ip,记录日志等等操作都可以在这里进行。

    public class KaptchaFormAuthenticationFilter extends FormAuthenticationFilter {
        
        final Logger logger = LoggerFactory.getLogger(getClass());
        
        private MessageSourceAccessor messageSourceAccessor;
        
        public KaptchaFormAuthenticationFilter(MessageSourceAccessor messageSourceAccessor) {
            this.messageSourceAccessor = messageSourceAccessor;
        }
    
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue)
                throws Exception {
            if (request.getAttribute(getFailureKeyAttribute()) != null) {
                return true;
            }
            return super.onAccessDenied(request, response, mappedValue);
        }
    
        @Override
        protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
                ServletResponse response) throws Exception {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            if ("XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"))) {
                httpServletResponse.setCharacterEncoding("UTF-8");
                PrintWriter out = null;
                try{
                    out = httpServletResponse.getWriter();
                    out.println(FastJsonUtils.toJSONString(ResultModel.defaultSuccess(null)));
                    out.flush();
                }finally{
                    if(out != null){
                        out.close();
                    }
                }
                return false;
            }
            
            return super.onLoginSuccess(token, subject, request, response);
            
        }
    
        @Override
        protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request,
                ServletResponse response) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            if ("XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"))) {
                String className = e.getClass().getName();
                ResultModel rm = new ResultModel(ResultStatus.FAIL.getCode(), messageSourceAccessor.getMessage(className));
                PrintWriter out = null;
                try {
                    out = httpServletResponse.getWriter();
                    out.println(FastJsonUtils.toJSONString(rm));
                    out.flush();
                } catch (IOException e1) {
                    if(logger.isInfoEnabled()){
                        e1.printStackTrace();
                    }
                }finally{
                    if(out != null){
                        out.close();
                    }
                }
                return false;
            }
            return super.onLoginFailure(token, e, request, response);
        }
    
        public MessageSourceAccessor getMessageSourceAccessor() {
            return messageSourceAccessor;
        }
    
        public void setMessageSourceAccessor(MessageSourceAccessor messageSourceAccessor) {
            this.messageSourceAccessor = messageSourceAccessor;
        }
    
    

    4、springboot配置shiroConfig

    package com.mos.easyboot.admin.config;
    
    import com.google.common.collect.Maps;
    import com.mos.easyboot.admin.config.service.impl.PermissionService;
    import com.mos.easyboot.admin.config.service.impl.UserService;
    import com.mos.easyboot.tools.shiro.KaptchaValidateFilter;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    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.filter.authc.FormAuthenticationFilter;
    import org.apache.shiro.web.filter.authc.LogoutFilter;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
    import org.springframework.context.MessageSource;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.DependsOn;
    import org.springframework.context.support.MessageSourceAccessor;
    
    import javax.servlet.Filter;
    import java.util.Map;
    
    /**
     * @author 小尘哥
     */
    @Configuration
    public class ShiroConfig{
    
    
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager securityManager(PermissionService permissionService) {
            DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
            manager.setRealm(userRealm(permissionService));
            return manager;
        }
    
        @Bean
        public MethodInvokingFactoryBean setSecurityManager(PermissionService permissionService) {
            MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
            methodInvokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
            methodInvokingFactoryBean.setArguments(securityManager(permissionService));
            return methodInvokingFactoryBean;
        }
    
        @Bean
        @DependsOn(value = "lifecycleBeanPostProcessor")
        public UserRealm userRealm(PermissionService permissionService) {
            UserRealm userRealm = new UserRealm(permissionService);
            userRealm.setCredentialsMatcher(credentialsMatcher());
            return userRealm;
        }
    
        @Bean
        public HashedCredentialsMatcher credentialsMatcher() {
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            credentialsMatcher.setHashAlgorithmName("MD5");
    //        credentialsMatcher.setHashIterations(2); MD5加密迭代次数1:MD5(str),2:MD5(MD5(str))
            return credentialsMatcher;
        }
    
        @Bean
        public FormAuthenticationFilter authcFilter(@Qualifier("messageSourceAccessor") MessageSourceAccessor messageSourceAccessor,
                                                    @Qualifier("userService") UserService userService) {
            CustomFormAuthenticationFilter authenticationFilter = new CustomFormAuthenticationFilter(messageSourceAccessor,userService);
            authenticationFilter.setLoginUrl("/login");
            return authenticationFilter;
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
                @Qualifier("permissionService") PermissionService permissionService) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager(permissionService));
            return authorizationAttributeSourceAdvisor;
        }
    
        public LogoutFilter logoutFilter() {
            LogoutFilter logout = new LogoutFilter();
            logout.setRedirectUrl("/login");
            return logout;
        }
        @Bean
        public KaptchaValidateFilter kaptchaValidate() {
            return new KaptchaValidateFilter();
        }
    
        @Bean(name = "shiroFilter")
        public ShiroFilterFactoryBean shiroFilter(@Qualifier("messageSourceAccessor") MessageSourceAccessor messageSourceAccessor,
                                                  @Qualifier("userService") UserService userService,
                                                  @Qualifier("permissionService") PermissionService permissionService) {
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            bean.setSecurityManager(securityManager(permissionService));
            bean.setLoginUrl("/toLogin");
            bean.setUnauthorizedUrl("/unauthor");
            bean.setSuccessUrl("/index");
    
            Map<String, Filter> filters = Maps.newHashMap();
            filters.put("kaptchaValidate", kaptchaValidate());
            filters.put("authc", authcFilter(messageSourceAccessor,userService));
            filters.put("logout", logoutFilter());
            bean.setFilters(filters);
    
            Map<String, String> filterChainDefinitionMap = Maps.newHashMap();
            filterChainDefinitionMap.put("/toLogin", "anon");
            filterChainDefinitionMap.put("/login*", "kaptchaValidate,authc");
            filterChainDefinitionMap.put("/logout", "logout");
            filterChainDefinitionMap.put("/demo/**", "anon");
            filterChainDefinitionMap.put("/kaptcha.jpg", "anon");
            filterChainDefinitionMap.put("/app/**", "anon");
            filterChainDefinitionMap.put("/images/**", "anon");
            filterChainDefinitionMap.put("/css/**", "anon");
            filterChainDefinitionMap.put("/js/**", "anon");
            filterChainDefinitionMap.put("/plugins/**", "anon");
            filterChainDefinitionMap.put("/**", "user");
    
            bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    
            return bean;
        }
    
        @Bean
        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
        @Bean
        public MessageSourceAccessor messageSourceAccessor(@Qualifier("messageSource") MessageSource messageSource){
            return new MessageSourceAccessor(messageSource);
        }
    }
    
    

    5、添加shiro拦截

        @Bean
        public FilterRegistrationBean shiroFilterRegistration() {
            FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
            filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
            filterRegistration.setEnabled(true);
            filterRegistration.addUrlPatterns("/*");
            filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
            return filterRegistration;
        }
    

    6、使用

    controller直接加@RequiresPermissions("对应的权限")或@RequiresRoles("对应的角色")即可
    模板上:<@shiro.hasPermission name="你定义的权限标识">/@shiro.hasPermission

    7、其他

    有些代码没有贴出来,随后我会把整个项目开源出来,easy-boot,基于springboot的快速开发框架搭建方案,希望大家多多支(tu)持(cao)····

    相关文章

      网友评论

        本文标题:springboot集成shiro

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