安全框架Shiro------------------介绍与使用

Shiro介绍

Shiro是Apache下的一个开源项目,它是一个比较简单容易使用的安全框架,它提供了认证,授权,加密,会话管理等功能

Shiro三大核心组件

Subject: 可理解成是当前用户主体,所有的Subject都会被绑定到一个SecurityManager中,跟Subject交互实质就是跟SecurityManager交互

SecurityManager: Shiro的核心,管理所有的Subject,它主要用于协调Shiro内部各种安全组件,可把它看成Shiro的管家

Realm: 可把它理解成是Shiro连接数据库的桥梁,无论Shiro进行认证还是授权都需要数据对比,而它就是Shiro去数据库拿数据的桥梁;改组件是由开发人员来写的,一般都是定义一个类继承AuthorizingRealm类,然后重写里面的方法

Shiro的常用用途

一般来说,我们使用Shiro都是用来进行认证,授权和会话(Session)管理

【认证】----------登陆的时候对用户的验证,如何验证是由开发人员来写的,会在Realm的认证方法中写对应的逻辑

【授权】----------对认证的用户进行赋予权限和角色,当某些方法访问需要权限和角色的时候就会触发验证,只有拥有对应的权限和角色才能进行访问,哪些方法访问需要权限或者角色也是由开发人员来规定的;

Shiro的简单使用

添加依赖

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

如果使用EhCache缓存的时候需要添加它的依赖
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>>1.4.0</version>
</dependency>

自定义Realm

public class MyRealm extends AuthorizingRealm
{
   
    //注意让自定义的Realm继承AuthorizingRealm类并重写它的认证,授权方法

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)
    {
        String userId = ShiroUtils.getUserId();    //这是获取认证的用户的id,能进入改方法证明用户通过了认证
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 角色加入AuthorizationInfo认证对象
        info.setRoles(参数是根据用户id从数据库中查出来的角色集合,Set集合来的);
        // 权限加入AuthorizationInfo认证对象
        info.setStringPermissions(参数是根据用户id从数据库中查出来的权限集合,Set集合来的);
        return info;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
    {
        //该对象是封装了用户账号更密码的一个对象,它是登陆那里记录的账号密码,不是从数据库查出来的账号密码
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;  
        String userId = upToken.getUsername();
        String password = "";
        if (upToken.getPassword() != null)
        {
            password = new String(upToken.getPassword());
        }

        Nurse user;
       
        user = 根据用户账号去数据库查询;   //这一步是根据账号去数据库查用户 
        
        if(user==null){
            throw new UnknownAccountException("用户名或密码错误!");  //抛出异常
        {
        //注意这几个参数,前面两个都是使用数据库查出来的数据,不是使用从参数token中获取的数据
        return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    }
}

配置Shiro

@Configuration
public class ShiroConfig {


    /**
     * 自定义Realm
     */
    @Bean
    public MyRealm myRealm()
    {
        MyRealm myRealm = new MyRealm();
        return myRealm;
    }

    /**
     * 安全管理器
     */
    @Bean
    public SecurityManager securityManager(MyRealm myRealm)
    {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(userRealm);
        return securityManager;
    }


    private LogoutFilter logoutFilter() { // 在ShiroFilterFactoryBean中使用
        LogoutFilter logoutFilter = new LogoutFilter();
        logoutFilter.setRedirectUrl("/login"); // 首页路径,登录注销后回到的页面
        return logoutFilter;
    }
    
    /**
     * 开启Shiro注解通知器,注意这个配置,如果没配置会导致注解无效
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
            @Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * Shiro过滤器配置
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager)
    {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // Shiro的核心安全接口,这个属性是必须的
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 身份认证失败,则跳转到登录页面的配置
        shiroFilterFactoryBean.setLoginUrl(路径);
        // 权限认证失败,则跳转到指定页面
        shiroFilterFactoryBean.setUnauthorizedUrl(路径);
        // Shiro连接约束配置,即过滤链的定义
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 对静态资源设置匿名访问
        filterChainDefinitionMap.put("/favicon.ico**", "anon");
        filterChainDefinitionMap.put("/ruoyi.png**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/docs/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/image/**", "anon");
        filterChainDefinitionMap.put("/ajax/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/druid/**", "anon");
        filterChainDefinitionMap.put("/plugins/**", "anon");
        filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
  
        // 不需要拦截的访问
        filterChainDefinitionMap.put("/login", "anon");
        Map<String, Filter> filters = new LinkedHashMap<>();
        // 注销成功,则跳转到指定页面
        filters.put("logout", logoutFilter());
        shiroFilterFactoryBean.setFilters(filters);
        // 所有请求需要认证
        filterChainDefinitionMap.put("/**", "user");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
}

使用认证功能

/**
     * 用户登录
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String login(User user) {
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getName(), user.getPassword());
        Subject subject = SecurityUtils.getSubject();  //获取shiro的实体对象
        try {
            // 登录操作
            subject.login(usernamePasswordToken);      //调用shiro中的认证方法对账号密码进行验证,这一行是重点,调用它才触发认证方法
            User user = (UserInfo) subject.getPrincipal();     //获取shiro中认证的主体对象
            return "index";
        } catch (Exception e) {
            return "login";
        }
    }

使用授权功能

/*
        一定要注意,只有使用了shiro的那些注解,才能使用授权功能,才有权限角色验证之说
        
        常用的几个注解:
        @RequiresPermissions("权限")----------这是权限注解,当用户拥有该权限时才能进行访问
        @RequiresRoles("角色")--------------这是角色注解,只有用户拥有该角色的时候才能进行访问
        @RequiresAuthentication()----------示当前Subject已经通过login 进行了身份验证,没有验证就报异常
        
        < shiro中的注解可以一起使用的 >
    */
    
--------使用例子:    
    
    /**
     * 删除用户
     */
    @RequiresPermissions("userInfo:del")                //只有使用了shiro的注解才会触发授权验证效果,这是注解之一
    @RequestMapping(value = "/del", method = RequestMethod.GET)
    public String del() {
        return "删除用户名 bobo 成功";
    }

以上的Shiro只是简单的使用,没有添加Ehcache缓存和加密,没有使用记住我,也没有使用Session管理

谢谢阅读,如果有错误之处,请指出!

这个链接的博主的shiro系列非常详细,可点击过去

相关推荐