首页 > 代码库 > springboot 集成shiro

springboot 集成shiro

首先看下shiro configuration 的配置,重要部分用红色标出了

package cn.xiaojf.today.shiro.configuration;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.xiaojf.today.sys.security.credentials.RetryLimitHashedCredentialsMatcher;
import cn.xiaojf.today.sys.security.filter.MyLogoutFilter;
import cn.xiaojf.today.sys.security.filter.RoleAuthorizationFilter;
import cn.xiaojf.today.sys.security.realm.UsernameRealm;
import cn.xiaojf.today.sys.service.SysResService;
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.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro配置
 * @author xiaojf 2017/2/10 11:30.
 */
@Configuration
public class ShiroConfiguration {
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new DelegatingFilterProxy("shiroFilter"));
        filterRegistrationBean.addInitParameter("targetFilterLifecycle", "true");
        filterRegistrationBean.setEnabled(true);
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }

    @Bean
    public RetryLimitHashedCredentialsMatcher credentialsMatcher() {
        RetryLimitHashedCredentialsMatcher credentialsMatcher = new RetryLimitHashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("sha");
        credentialsMatcher.setHashIterations(2);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        credentialsMatcher.setRetryCount(5);
        credentialsMatcher.setRetryTime(1800000);
        return credentialsMatcher;
    }

    @Bean
    public UsernameRealm usernameRealm(RetryLimitHashedCredentialsMatcher credentialsMatcher) {
        UsernameRealm usernameRealm = new UsernameRealm();
        usernameRealm.setCredentialsMatcher(credentialsMatcher);
        usernameRealm.setCachingEnabled(true);
        return  usernameRealm;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(UsernameRealm usernameRealm) {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setRealm(usernameRealm);
        return dwsm;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(defaultWebSecurityManager);
        return aasa;
    }

    @Bean
    public MyLogoutFilter logoutFilter() {
        MyLogoutFilter myLogoutFilter = new MyLogoutFilter();
        myLogoutFilter.setRedirectUrl("/login/index");
        return myLogoutFilter;
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager,
                                                         MyLogoutFilter logoutFilter, ApplicationContext context) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login/index");
        shiroFilterFactoryBean.setUnauthorizedUrl("/login/index");

        Map<String, Filter> filters = new LinkedHashMap<>();
//        filters.put("logout", logoutFilter);
        filters.put("role", new RoleAuthorizationFilter());

        shiroFilterFactoryBean.getFilters().putAll(filters);//加载自定义拦截器

        SysResService resService = context.getBean(SysResService.class);//只有通过这种方式才能获得resService,因为此处会优先于resService实例化
        loadShiroFilterChain(shiroFilterFactoryBean,resService);//加载拦截规则
        return shiroFilterFactoryBean;
    }

    private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean,SysResService resService) {
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
     //默认拦截规则 filterChainDefinitionMap.put(
"/login/index", "anon"); filterChainDefinitionMap.put("/error/403", "anon"); filterChainDefinitionMap.put("/error/404", "anon"); filterChainDefinitionMap.put("/error/500", "anon"); filterChainDefinitionMap.put("/login/auth", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/plugins/**", "anon"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/images/**", "anon");      //用户自定义拦截规则 filterChainDefinitionMap = resService.loadFilterChainDefinitions(filterChainDefinitionMap);      //都不满足的时候,需要超级管理员权限才能访问 filterChainDefinitionMap.put("/**", "role[ROLE_SUPER]");      shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); } @Bean public ShiroDialect shiroDialect() {//thymeleaf 集成shiro使用,如果没有可以删除 return new ShiroDialect(); } }

自定义realm,用于认证和授权

package cn.xiaojf.today.sys.security.realm;

import cn.xiaojf.today.base.constant.DataStatus;
import cn.xiaojf.today.base.constant.SystemConstant;
import cn.xiaojf.today.sys.entity.SysUser;
import cn.xiaojf.today.sys.service.SysUserService;
import org.apache.shiro.authc.*;
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.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.Set;

/**
 * 根据用户名和密码校验登陆
 *
 * @author xiaojf 2016-01-07 16:05:55
 */
public class UsernameRealm extends AuthorizingRealm {

    /**
     * 系统用户service
     */
    @Autowired
    @Lazy
    private SysUserService sysUserService;

    /**
     * 加载用户授权信息, 包括权限资源和角色\用户组资源
     *
     * @author xiaojf 2016-01-07 16:05:55
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        // 登陆名
        String username = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        Set<String> roles = sysUserService.loadEnabledRolesByUsername(username);

        if (roles.contains(SystemConstant.ROLE_SUPER)) {
            authorizationInfo.addStringPermission("*");
        }else {
            // 加载权限资源
            authorizationInfo.setStringPermissions(sysUserService.loadEnabledPermissionsByUsername(username));
        }

        // 加载角色/用户组
        authorizationInfo.setRoles(roles);

        return authorizationInfo;
    }

    /**
     * 加载用户身份认证信息
     *
     * @author xiaojf 2016-01-07 16:05:55
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();

        // 获取账号信息
        SysUser sysUser = sysUserService.getByUsername(username);

        if (sysUser == null) {
            throw new UnknownAccountException();    // 没找到帐号
        }

        if (sysUser.getStatus() == DataStatus.LOGIC_DELETE.getValue()) {
            throw new UnknownAccountException();    // 没找到帐号
        }

        if (sysUser.getStatus() == DataStatus.DISABLE.getValue()) {
            throw new LockedAccountException();    // 帐号锁定
        }

        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(sysUser.getUsername(),
                sysUser.getPwd(), ByteSource.Util.bytes(sysUser.getSalt()),
                getName());

        return authenticationInfo;
    }

}

自定义登出过滤器

package cn.xiaojf.today.sys.security.filter;

import org.apache.shiro.web.filter.authc.LogoutFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * 自定义退出过滤器
 * @author xiaojf 294825811@qq.com
 *
 * 2015-3-20
 */
public class MyLogoutFilter extends LogoutFilter {
    
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        return true;
    }
}

自定义权限校验过滤器

package cn.xiaojf.today.sys.security.filter;

import com.alibaba.fastjson.JSON;
import cn.xiaojf.today.base.model.CommonResult;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;

/**
 * 自定义认证器,区分ajax请求
 * @author xiaojf 2017/2/10 11:30.
 */
public class RoleAuthorizationFilter extends AuthorizationFilter {

    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws IOException {

        Subject subject = getSubject(request, response);
        String[] rolesArray = (String[]) mappedValue;

        if (rolesArray == null || rolesArray.length == 0) {
            // no roles specified, so nothing to check - allow access.
            return true;
        }

        Set<String> roles = CollectionUtils.asSet(rolesArray);
        for (String role : roles) {
            if (subject.hasRole(role)) {
                return true;
            }
        }
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        Subject subject = getSubject(request, response);

        if (subject.getPrincipal() == null) {
            if ("XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"))) {
                httpServletResponse.setCharacterEncoding("UTF-8");
                httpServletResponse.setHeader("Charset","UTF-8");
                PrintWriter out = httpServletResponse.getWriter();

                CommonResult result = new CommonResult(false);
                result.setCode("401");
                result.setMsg("请重新登录");

                out.write(JSON.toJSONString(result));
                out.flush();
                out.close();
            } else {
//                saveRequestAndRedirectToLogin(request, response);
                String unauthorizedUrl = getUnauthorizedUrl();
                WebUtils.issueRedirect(request, response, unauthorizedUrl);
            }
        } else {
            if ("XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"))) {
                httpServletResponse.setCharacterEncoding("UTF-8");
                httpServletResponse.setHeader("Charset","UTF-8");
                PrintWriter out = httpServletResponse.getWriter();

                CommonResult result = new CommonResult(false);
                result.setCode("403");
                result.setMsg("没有足够的权限: "+((HttpServletRequest) request).getServletPath());

                out.println(JSON.toJSONString(result));
                out.flush();
                out.close();
            } else {
                String unauthorizedUrl = getUnauthorizedUrl();
                if (StringUtils.hasText(unauthorizedUrl)) {
                    WebUtils.issueRedirect(request, response, unauthorizedUrl);
                } else {
                    WebUtils.toHttp(response).sendError(403);
                }
            }
        }
        return false;
    }
}

 

springboot 集成shiro