SpringBoot整合Shiro做登录认证和鉴权授权

登录认证

1、先把shiro环境搭起来

<dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-coreartifactId>
            <version>1.3.2version>
        dependency>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>1.3.2version>
        dependency>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-webartifactId>
            <version>1.3.2version>
        dependency>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-ehcacheartifactId>
            <version>1.3.2version>
        dependency>

2、规定加密规则,并做一些测试数据
创建一个类ShiroUtil,封装这些操作

import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import java.util.HashMap;
import java.util.Map;

public class ShiroUtil {
    static final String SHA="SHA-1";
    static final Integer COUNT=369;//加密次数
	//生成测试数据
    public static void main(String[] args) {
        Map<String, String> map = encodePassword("123456");
        System.out.println(map);
    }

    //生成混淆字符串(盐)
    public static String generateSalt(){
        SecureRandomNumberGenerator salt = new SecureRandomNumberGenerator();
        return salt.nextBytes().toHex();
    }

    //加密
    public static String encode(String input,String salt){
        return new SimpleHash(SHA,input,salt,COUNT).toString();
    }

    //详细信息
    public static Map<String,String> encodePassword(String input){
        Map<String,String> map=new HashMap<>();
        String salt=generateSalt();
        String password = encode(input, salt);
        map.put("salt",salt);
        map.put("password(明文)",input);
        map.put("password(密文)",password);
        return map;
    }
}

3、写一大堆Shiro的配置,封装在配置类里

import com.apesource.common.MyRealm;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
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.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.DependsOn;
import org.springframework.scheduling.annotation.EnableScheduling;

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

@Configuration
public class ShiroConfig {
    //创建shiro自带的cookie对象
    @Bean
    public SimpleCookie sessionIdCookie(){
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName("ShiroSession");
        return simpleCookie;
    }

    //创建realm
    @Bean
    public MyRealm getRealm(){
        return new MyRealm();
    }

    //创建会话管理器
    @Bean
    public DefaultWebSessionManager sessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(sessionIdCookie());
        sessionManager.setGlobalSessionTimeout(3600000);
        return sessionManager;
    }

    //创建安全管理器
    @Bean
    public SecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }
    /**
     * 5.保证实现了Shiro内部lifecycle函数的bean执行
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 6.开启对shior注解的支持
     *   AOP式方法级权限检查
     *   @DependsOn意思是我这个组件要依赖于另一个组件,也就是说被依赖的组件会比该组件先注册到IOC容器中
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 7.配合DefaultAdvisorAutoProxyCreator事项注解权限校验
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());
        return authorizationAttributeSourceAdvisor;
    }
    //8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制
    @Bean
    public ShiroFilterFactoryBean shiroFilter() {
        //1.创建过滤器工厂
        ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
        //2.设置安全管理器
        filterFactory.setSecurityManager(defaultWebSecurityManager());
        //3.通用配置(跳转登录页面,为授权跳转的页面)
        filterFactory.setLoginUrl("/authentic_error");//跳转url地址
        //4.设置过滤器集合
        //key = 拦截的url地址
        //value = 过滤器类型
        Map<String,String> filterMap = new LinkedHashMap<>();
        //key:请求规则   value:过滤器名称
        filterMap.put("/xxx/login","anon");//当前请求地址可以匿名访问
        filterMap.put("/xxx/*","authc");//当前请求地址必须认证之后可以访问
       
        //在过滤器工程内设置系统过滤器
        filterFactory.setFilterChainDefinitionMap(filterMap);
        return filterFactory;
    }
}

重点看第八个配置,如果用户还没有认证,就不能访问xxx目录下的其他地址。只有login可以登录。
4、认证登录,创建MyRealm继承AuthorizingRealm,重写类中的方法

//认证(authentic)
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登录的用户名密码(username-password)
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //登录的用户的用户名
        String username = token.getUsername();
        System.out.println("登录用户:"+username);
        //根据username去数据库查表,获得emp对象(emp的基本信息)
        Employee employee = service.findEmpByUsername(username);
        //查到emp的全部信息,包括用户的角色权限(多表联查)
        Employee empData = service.findEmpAndRole(employee.getId());
        System.out.println("数据库用户数据:"+empData.toString());
        if(empData!=null){
            System.out.println("数据库有这个数据");
            SimpleAuthenticationInfo info =
                    new SimpleAuthenticationInfo(empData,empData.getPassword(),
                           ByteSource.Util.bytes(empData.getSalt()),this.getName());
            System.out.println("登录用户:"+info);
            return info;
        }
        return null;
    }
    /**
     * @Description 自定义密码比较器
     * @param
     * @return
     * bean标签 init-method属性
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        //指定密码算法
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher("SHA-1");
        //指定迭代次数
        hashedCredentialsMatcher.setHashIterations(369);
        //生效密码比较器
        setCredentialsMatcher(hashedCredentialsMatcher);
    }
    

鉴权授权

1、建立角色表、权限表、角色权限关系表、角色用户关系表,做五表联查
SpringBoot整合Shiro做登录认证和鉴权授权_第1张图片
级联步骤:
http://t.csdn.cn/plVrn
2、MyRealm中重写doGetAuthorizationInfo方法

//授权(authorize)
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //1.获取已认证的用户数据(已经登录的用户)
        Employee employee = (Employee) principalCollection.getPrimaryPrincipal();//得到唯一的安全数据
        System.out.println("授权用户:"+employee);
        //2.根据用户数据获取用户的权限信息(所有角色,所有权限)
        Set<String> roles = new HashSet<>();//所有角色
        Set<String> perms = new HashSet<>();//所有权限
        for (Role role : employee.getRoleList()) {
            roles.add(role.getRoleName());
            for (Permission perm : role.getPermissionList()) {
            //code中的字符串保存了权限信息,@RequiresPermissions("xxx")可用
                perms.add(perm.getCode());
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(perms);
        info.setRoles(roles);
        return info;
    }

3、在需要特定权限的方法上加注解:@RequiresPermissions(“权限”)

你可能感兴趣的:(spring,boot,java,spring)