SpringBoot整合Shiro框架

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。
因为它轻量级所以被广泛的用到Java项目中。
今天我们将它整合到SpringBoot的框架中。

添加Maven依赖

在pom.xml中添加依赖

<dependency>
 <groupId>org.apache.shiro</groupId>
 <artifactId>shiro-spring</artifactId>
 <version>1.4.0</version>
</dependency>

新建shiro的配置文件和realm

ShiroConfiguration.java

package com.ntsd.df_back.shiro;



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.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;
import java.util.Map;


/**
 * shiro配置类
 * Created by pythonsir on 2020/04/07.
 */
@Configuration
public class ShiroConfiguration {

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


    @Bean(name = "shiroRealm")
    @DependsOn("lifecycleBeanPostProcessor")
    public ShiroRealm shiroRealm(){
        ShiroRealm shiroRealm = new ShiroRealm();
       // 设置密码验证类
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return  shiroRealm;
    }
    // 密码验证类
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setStoredCredentialsHexEncoded(false);
        return credentialsMatcher;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        return  securityManager;
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(){

        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager());

        Map<String,String> filterChainDefinitions = new LinkedHashMap<String, String>();
        filterChainDefinitions.put("/loginOut", "logout");
        filterChainDefinitions.put("/main", "authc");
        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitions);
        shiroFilter.setSuccessUrl("/main");
        shiroFilter.setUnauthorizedUrl("/403");
        shiroFilter.setLoginUrl("/");
        return  shiroFilter;
    }

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

ShiroRealm.java

package com.ntsd.df_back.shiro;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ntsd.df_back.config.LdapConfig;
import com.ntsd.df_back.exception.LdapException;
import com.ntsd.df_back.module.systerm.entity.SysUserBack;
import com.ntsd.df_back.module.systerm.form.LoginForm;
import com.ntsd.df_back.module.systerm.service.ISysUserBackService;
import com.ntsd.df_back.module.systerm.service.ISysUserRoleService;
import org.apache.shiro.SecurityUtils;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.management.Query;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

public class ShiroRealm  extends AuthorizingRealm {

    @Autowired
    private ISysUserBackService iSysUserBackService;

    @Autowired
    private ISysUserRoleService iSysUserRoleService;

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

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

        QueryWrapper<SysUserBack> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",userName);

        SysUserBack user = iSysUserBackService.getOne(queryWrapper);

        Set<String> roles = iSysUserRoleService.getAllRole(user.getUserName());

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        authorizationInfo.setRoles(roles);

        Session session = SecurityUtils.getSubject().getSession();

        if(null == session.getAttribute("user")){
            session.setAttribute("user",user);
        }
        session.setAttribute("role",roles);

        return authorizationInfo;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String userName = (String)authenticationToken.getPrincipal();  //得到用户名
        String password = new String((char[])authenticationToken.getCredentials()); //得到密码

       

        QueryWrapper<SysUserBack> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",userName);


        SysUserBack user = iSysUserBackService.getOne(queryWrapper);

        if(null == user){
            throw  new UnknownAccountException(); // 没有找到账号
        }
        Session session = SecurityUtils.getSubject().getSession();

        session.setAttribute("user",user);
       //密码验证校验
        return new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(), ByteSource.Util.bytes(user.getUserName()),getName());
    }
}

上述文件直接拷贝到SpringBoot项目中使用。
至此SpringBoot就接入了Shiro框架。

对密码进行加密

在控制器中进行操作,代码如下:

package com.ntsd.df_back.module.systerm.controller;


import com.ntsd.df_back.module.systerm.entity.SysUserBack;
import com.ntsd.df_back.module.systerm.service.ISysUserBackService;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * <p>
 * ????? 前端控制器
 * </p>
 *
 * @author pythonsir
 * @since 2020-05-08
 */
@Controller
@RequestMapping("/systerm/user")
public class SysUserBackController {

    @Autowired
    private ISysUserBackService iSysUserBackService;

    //新增用户保存到数据库
    @RequestMapping("create")
    @ResponseBody
    public String create(@RequestParam(name = "userName") String userName,@RequestParam(name = "password") String password){

        SysUserBack sysUserBack = new SysUserBack();
        sysUserBack.setUserName(userName.trim());
         //盐
        Object salt = ByteSource.Util.bytes(userName.trim());
        SimpleHash simpleHash = new SimpleHash("MD5",password,salt,1);
        //数据库中存储的密码一定是 simpleHash.toBase64()
        //千万不要使用 simpleHash.toString(),否则会直接报密码错误
        sysUserBack.setPassword(simpleHash.toBase64());
        sysUserBack.setIsEnabled(1);
        iSysUserBackService.save(sysUserBack);
        return "success";
    }

}

使用注解进行角色权限控制

在控制器或者方法上面增加注解

角色控制

@Controller
@RequiresRoles("admin")
public class TestController{
...
}
  • 需要拥有admin的角色访问控制器

权限控制

@Controller
@RequiresPermissions(value = {"test:add","test:deal","test:archive"},logical = Logical.OR)
public class TestController{
...
}
  • 上面代码当前用户只要拥有"test:add","test:deal","test:archive"中的任何一个权限都可以访问控制器

说明

上述代码可直接用于项目中,只需复制粘贴即可,关注老夫撸代码,杜绝996!

SpringBoot整合Shiro框架