Shiro原理流程,代码示例

Posted 宇宙磅礴而冷漠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shiro原理流程,代码示例相关的知识,希望对你有一定的参考价值。

Shiro组成流程图解

功能介绍:
主要实现用户身份认证,权限授权、加密、会话管理。
组成:
在这里插入图片描述
解释:

  1. Subject(主体):与软件交互的一个特定的实体(用户、第三方服务等)。
  2. SecurityManager(安全管理器) :Shiro 的核心,用来协调管理组件工作。
  3. Authenticator(认证管理器):负责执行认证操作。
  4. Authorizer(授权管理器):负责授权检测。
  5. SessionManager(会话管理):负责创建并管理用户 Session 生命周期,提供一
    个强有力的 Session 体验。
  6. SessionDAO:代表 SessionManager 执行 Session 持久(CRUD)动作,它允
    许任何存储的数据挂接到 session 管理基础上。
  7. CacheManager(缓存管理器):提供创建缓存实例和管理缓存生命周期的功能,对Session和授权数据进行缓存。
  8. Cryptography(加密管理器):提供了加密方式的设计及管理。
  9. Realms(领域对象):是 shiro 和你的应用程序安全数据之间的桥梁,Realm存储授权和认证的逻辑。
    主要工作流程:
    在这里插入图片描述

代码示例

依赖

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

核心配置

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;

@Configuration
public class SpringShiroConfig {
    @Bean
    public SecurityManager securityManager(Realm realm,CacheManager cacheManager,RememberMeManager rememberMeManager,SessionManager sessionManager){
        //web应用中,这个接口的具体实现建议DefaultWebSecurityManager
        //DefaultSecurityManager不一样
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        securityManager.setCacheManager(cacheManager);
        securityManager.setRememberMeManager(rememberMeManager);
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }
    //配置认证过滤规则,哪些资源需要认证访问,哪些资源可以匿名访问
    //规则我们来定义,规则的检验是在shiro框架中借助大量过滤器(Filter)去实现。
    //shiro提供了过滤类型,但是基于类型创建其实例需要通过过滤器工厂
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean filterFactoryBean=new ShiroFilterFactoryBean();
        LinkedHashMap<String,String> map=new LinkedHashMap<>();
        //存储规则key为资源名,value为规则
        map.put("/bower_components/**","anno" );//anno为匿名访问,shiro定义字符串
        map.put("/build/**","anno" );
        map.put("/dist/**","anno" );
        map.put("/plugins/**","anno" );
        map.put("/user/doLogin","anno" );
        map.put("/doLogout","logout" );//退出时会自动回到登陆界面
        //除了以上资源,后续所有资源都要认证访问
        map.put("/**","authc" );//authc表示需要认证

        //map.put("/**","user" );//表示可以从客户端获取信息
        //如何判定访问这个资源时是否已经认证过了呢?
        filterFactoryBean.setSecurityManager(securityManager);
        //假如访问时还没有通过认证?跳转到指定认证页面
        filterFactoryBean.setLoginUrl("/doLoginUI");
        filterFactoryBean.setFilterChainDefinitionMap(map);
        return filterFactoryBean;
    }
    //顾问对象
    //负责找到类中使用此注解@RequiresPermissions描述的方法,
    //这些方法为授权访问切入点方法,当执行这些方法时会由通知(Advice)对象
    //调用一个对象(securityManager)完成权限检测及授权
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor a=new AuthorizationAttributeSourceAdvisor();
        a.setSecurityManager(securityManager);
        return a;
    }
    @Bean
    //缓存管理器,频繁访问数据库
    public CacheManager shirocachemanager(){
        return new MemoryConstrainedCacheManager();
    }

    public RememberMeManager rememberMeManager(){
        CookieRememberMeManager rememberMeManager=
                new CookieRememberMeManager();
        SimpleCookie cookie=new SimpleCookie("rememberMe");
        cookie.setMaxAge(7*24*60*60);
        rememberMeManager.setCookie(cookie);
        return rememberMeManager;
    }

    public SessionManager sessionManager(){
        DefaultWebSessionManager sessionManager=
                new DefaultWebSessionManager();
        sessionManager.setGlobalSessionTimeout(1800000L*2);//1 hour
        //服务器重启丢掉用户cookie
        sessionManager.setSessionIdUrlRewritingEnabled(false);//不想要用false
        return sessionManager;
    }
}

认证授权

import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
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.stereotype.Service;
import java.util.HashSet;
import java.util.Set;

@Service
public class ShiroUserRealm extends AuthorizingRealm {
    //继承AuthorizingRealm授权和认证
    //继承AuthenticatingRealm(只认证)
    //Realm可获取认证数据信息和授权数据信息
    @Autowired
    private SysUserDao sysUserDao;//自定义的接口
    @Override
    //用于获取用户的权限信息并封装
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取登陆用户
        SysUser user=(SysUser)principalCollection.getPrimaryPrincipal();
        //获取登陆用户的角色权限数据
        List<String> perssion=sysMenuDao.findPermisisin(user.getId());
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        Set<String> setPerssion=new HashSet<>();
       	for(String per:perssion){
       		if(!StringUtils.isEmpty(per)){
 				set.add(per);
 			}
       	}
       	info.setStringPermissions(setPerssion);
        //封装数据并返回,交给securityManager
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登陆时输入的用户名
        UsernamePasswordToken upt=(UsernamePasswordToken)authenticationToken;
        String username=upt.getUsername();
        //基于用户名查找数据库信息
        SysUser sysUser=sysUserDao.findUserByUsername(username);
        //校验用户是否已被禁用
        if(sysUser==null){
            throw new UnknownAccountException();
        }
        if(sysUser.getValid()==0){
            throw new LockedAccountException();
        }
        //封装用户信息,交给securityManager进行认证
        ByteSource credentialsSalt=ByteSource.Util.bytes(sysUser.getSalt());
        SimpleAuthenticationInfo info=
                new SimpleAuthenticationInfo(sysUser,
                        sysUser.getPassword(),
                        credentialsSalt,getName());
        return info;
    }
	//get和set选一个就行
    //@Override
    //public CredentialsMatcher getCredentialsMatcher() {
       // HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher("MD5");
        //credentialsMatcher.setHashIterations(1);
        //return credentialsMatcher;
    //}
    @Override
	public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
		//构建凭证匹配对象
		HashedCredentialsMatcher cMatcher=new HashedCredentialsMatcher();
		//设置加密算法
		cMatcher.setHashAlgorithmName("MD5");
		//设置加密次数
		cMatcher.setHashIterations(1);
		super.setCredentialsMatcher(cMatcher);
	}
}

用户登录记录令牌

//controller层
 public JsonResult doLogin(String name,String password){
        //获取用户名,aop里记录日志可以用
		//(SysUser)SecurityUtils.getSubject().getPrincipal();
        UsernamePasswordToken token = new UsernamePasswordToken(name,password);
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
        return new JsonResult("login ok");
 }

service层标识权限

 //授权访问切入点方法,标识在service层的类或方法上
 @RequiresPermissions(value = "sys:user:update")

以上是关于Shiro原理流程,代码示例的主要内容,如果未能解决你的问题,请参考以下文章

debug代码解析shiro认证流程

全栈编程系列SpringBoot整合Shiro(含KickoutSessionControlFilter并发在线人数控制以及不生效问题配置启动异常No SecurityManager...)(代码片段

Shiro权限管理框架:Shiro中权限过滤器的初始化流程和实现原理

Shiro授权认证原理和流程

Shiro 安全框架详解二(概念+权限案例实现)

Shiro安全框架SpringBoot版