shrio简介

1、环境搭建

1、在web.xml中配置过滤器

 
    
        shiroFilter
        
            org.springframework.web.filter.DelegatingFilterProxy
        
        
            targetFilterLifecycle
            true
        
        
    
    
        shiroFilter
        /*
    

注意,过滤器的名字shiroFilter可以自定义,但是spring配置文件中的bean的id默认要与该filter-name相同,如果想要改变默认设置,可以配置targetBeanName属性

2、在spring配置文件中集成shrio

 
    
        
        
        
        
    

    
    
        
    

    
    
        
        
            
                
                
                
                
            
        
    

    
    

    
    
    
        
    

    
    
        
        
        
        
        
        
       
    

    
    


    
    
    
        
        
        
        
    

    
    
        
        
        
    
    

shiro框架的一切功能都是围绕securityManager展开,所以集成shiro最核心的bean就是org.apache.shiro.web.mgt.DefaultWebSecurityManager,在这个bean中可以实现缓存、认证授权和记住我等多种功能。除了securityManager,还有一个配置也很重要,那就是之前配置在web.xml中的过滤器的工厂org.apache.shiro.spring.web.ShiroFilterFactoryBean。这个bean的id默认与filter-name相同,它的内部持有了securityManage实例,内部可以配置认证成功后指向的资源、认证资源和未授权指向的资源以及角色权限配置。

2、shiro配置详解

注:shiro中的资源指服务器内一切内容,包括java代码、接口、js、css、图片和一切其他资源

1、过滤器工厂类


    
        
        
        
        
    

这个类用来生成过滤器实例,并且提供了众多属性供过滤器使用:







还可以配置shiro的授权,有两种配置方法

1、在配置文件中写入

 

            
                /user/login = anon
                /user/registerView = anon
                /user/register = anon
                /user/logout = logout
                /user/addView = roles[emp]
                /user/modifyView = roles[manager]
                /user/removeView = roles[admin]
                /user/** = user
                /static/** = anon
            

2、自己创建工厂生成filterChainDefinitionMap

shiroFilter中有一个filterChainDefinitionMap对象属性,它是一个实现了Map接口的对象,我们可以利用自建工厂添加拦截配置




这里是shiroFilter的filterChainDefinitionMap属性配置



工厂类由自己实现 类名称和方法自行定义,这里使用了如下实现

package com.fan.shiro.util;

import com.fan.shiro.pojo.FilterChainDefinition;
import com.fan.shiro.service.IFilterChainDefinitionService;
import org.springframework.beans.factory.annotation.Autowired;


import java.util.LinkedHashMap;
import java.util.List;


public class FilterChainDefinitionMapBuilder {
    @Autowired
    private IFilterChainDefinitionService filterChainDefinitionService;

    public LinkedHashMap buildFilterChainDefinitionMap() {
        //调用业务层从数据库中查出拦截资源的列表
        List filterChainDefinitions = filterChainDefinitionService.findAllFilterChainDefinition();
        LinkedHashMap map = new LinkedHashMap<>();
        for (FilterChainDefinition f : filterChainDefinitions) {
            map.put(f.getApi(), f.getFilter());
        }
        return map;
    }
}

3、注意

1、不论在配置文件中直接配置,还是利用工厂返回map,拦截资源的配置都是按照顺序先后执行,例如:


            
                
                /user/register = anon
                /user/register = authc
                 
                /user/** = anon
                /user/modifyView = authc
                /user/removeView = user
            


所以,即使在数据库中添加配置数据的时候也一定要注意先后顺序。

2、权限和认证(记住我)可以进行组合

比如:authc,roles[pay]表示这个角色必须在认证后才能生效,在记住我状态时无法访问,必须先登录认证

2、securityManager

securityManager是shiro的核心,重要功能都需要它实现

1、缓存



这里使用了ecach缓存

 

    


2、realm实现认证和授权



realm想要同时具有认证和授权的功能,需要继承AuthorizingRealm类

 

    
    
        
            
            
        
    


以下是reaml的实现

package com.fan.shiro.realms;

import com.fan.shiro.pojo.Permission;
import com.fan.shiro.pojo.Role;
import com.fan.shiro.pojo.User;
import com.fan.shiro.service.IPermissionService;
import com.fan.shiro.service.IRoleService;
import com.fan.shiro.service.IUserService;
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 java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    IUserService userService;
    @Autowired
    IRoleService roleService;
    @Autowired
    IPermissionService permissionService;

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //从authenticationToken取出UsernamePasswordToken
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userName = token.getUsername();
        User user = userService.findUserByUserName(userName);
        if (user == null) {
            throw new UnknownAccountException("用户不存在!");
        }
        if (user.getStatus().equals("0")) {
            throw new LockedAccountException("该用户已被锁定!");
        }
        //获取盐值
        ByteSource byteSource = ByteSource.Util.bytes(userName);
        //通过盐值加密验证用户 密码不匹配会抛出IncorrectCredentialsException异常
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), byteSource, this.getName());
        //通过验证后将用户对象存储到session中
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute("userInfo", user);
        return simpleAuthenticationInfo;
    }

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        User user = (User) principalCollection.getPrimaryPrincipal();
        Set roles = new HashSet<>();
        //查出用户的角色 并将所有角色添加到set集合中
        List roleList = roleService.findRoleByUserId(user.getUserId());
        for (Role r : roleList) {
            roles.add(r.getRoleName());
        }
        //将set注入到SimpleAuthorizationInfo实例中
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles);
        //查出用户权限
        List permissionList = permissionService.findPermissionByUserId(user.getUserId());
        List permissions = new ArrayList<>();
        for (Permission p : permissionList) {
            permissions.add(p.getPermissionName());
        }
        //调用addStringPermissions将权限列表加入simpleAuthorizationInfo
        simpleAuthorizationInfo.addStringPermissions(permissions);
        //返回实例 告知shiro框架该用户具有的角色和权限
        return simpleAuthorizationInfo;
    }
}

3、rememberMe记住我

记住我功能与认证功能不一样,记住我功能开启后,shiro会检测客户端是否有rememberme cookie,如果有就会对该cookie进行验证,如果没有就会生成一个cookie并返回给客户端。在拦截配置中user关键字就是针对记住我。==记住我在controller中必须在Subject的login方法之前调用==



    
    
    
    
 


    
    
    
    


3、其它配置

 
    

    
    
        
    
    
        
    

4、controller层如何实现认证

 @RequestMapping("/login")
    @ResponseBody
    public ResponseResult login(User user, String remember) {
        ResponseResult responseResult = new ResponseResult("200", "登录成功!");
        //1、获取当前Subject用户
        Subject currentUser = SecurityUtils.getSubject();
        //2、判断当前用户是否已经认证过
        if (currentUser.isAuthenticated()) {
            responseResult.setCode("200");
            responseResult.setMessage("用户已登录!");
            return responseResult;
        }
        //3、获得UsernamePasswordToken
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
        //4、进行用户身份验证
        try {
            //4.1判断用户是否设置了记住我选项,该方法必须在认证之前调用
            boolean flag = false;
            if (remember != null) {
                flag = "remember".equals(remember);
            }
            token.setRememberMe(flag);
            //4.2 调用Subject的login方法进行验证 如果验证不通过会抛出异常在catch中处理 验证通过则将用户加入
            //session中
            currentUser.login(token);
        } catch (UnknownAccountException uae) {
            responseResult.setCode("404");
            responseResult.setMessage("用户不存在!");
            return responseResult;
        } catch (IncorrectCredentialsException ice) {
            responseResult.setCode("400");
            responseResult.setMessage("密码错误!");
            return responseResult;
        } catch (LockedAccountException lae) {
            responseResult.setCode("300");
            responseResult.setMessage("该用户已被锁定!");
            return responseResult;
        } catch (AuthenticationException ae) {
            responseResult.setCode("500");
            responseResult.setMessage("登录失败,请重试!");
            return responseResult;
        }
        return responseResult;
    }

3、总结

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序,JavaSE环境和JavaEE环境都可以使用 (抄来的)

你可能感兴趣的:(shrio简介)