SpringBoot整合Shiro配置详解

一.shiro基本介绍

1、Shiro是Apache下的一个开源项目,我们称之为Apache Shiro。它是一个很易用与Java项目的的安全框架,提供了认证、授权、加密、会话管理,与spring Security 一样都是做一个权限的安全框架,但是与Spring Security 相比,在于 Shiro 使用了比较简单易懂易于使用的授权方式。shiro属于轻量级框架,相对于security简单的多,也没有security那么复杂。所以我这里也是简单介绍一下shiro的使用。

2、非常简单;其基本功能点如下图所示:

SpringBoot整合Shiro配置详解_第1张图片

Authentication身份认证/登录,验证用户是不是拥有相应的身份;

Authorization授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

Session Manager会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

Cryptography加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web SupportWeb支持,可以非常容易的集成到Web环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrencyshiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing提供测试支持;

Run As允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

High-Level Overview 高级概述

在概念层,Shiro 架构包含三个主要的理念:Subject,SecurityManager和 Realm。下面的图展示了这些组件如何相互作用,我们将在下面依次对其进行描述。

  • Subject:当前用户,Subject 可以是一个人,但也可以是第三方服务、守护进程帐户、时钟守护任务或者其它–当前和软件交互的任何事件。
  • SecurityManager:管理所有Subject,SecurityManager 是 Shiro 架构的核心,配合内部安全组件共同组成安全伞。
  • Realms:用于进行权限信息的验证,我们自己实现。Realm 本质上是一个特定的安全 DAO:它封装与数据源连接的细节,得到Shiro 所需的相关的数据。在配置 Shiro 的时候,你必须指定至少一个Realm 来实现认证(authentication)和/或授权(authorization)。

我们需要实现Realms的Authentication 和 Authorization。其中 Authentication 是用来验证用户身份,Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。

记住一点,Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro即可。

二.配置信息

1.添加maven依赖


   org.apache.shiro
   shiro-core
   1.4.0


   org.apache.shiro
   shiro-spring
   1.4.0

2.Shiro配置类

@Configuration
public class ShiroConfigBean {

    //配置自定义的权限登录器
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }
    //session管理器
    @Bean("sessionManager")
    public SessionManager sessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setSessionIdCookieEnabled(true);
        return sessionManager;
    }

    //配置核心安全事务管理器
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }

    
    /**
     * 注册DelegatingFilterProxy(Shiro)
     * 集成Shiro有2种方法:
     * 1. 按这个方法自己组装一个FilterRegistrationBean(这种方法更为灵活,可以自己定义UrlPattern,
     * 在项目使用中你可能会因为一些很但疼的问题最后采用它, 想使用它你可能需要看官网或者已经很了解Shiro的处理原理了)
     * 2. 直接使用ShiroFilterFactoryBean(这种方法比较简单,其内部对ShiroFilter做了组装工作,无法自己定义UrlPattern,
     * 默认拦截 /*)
     *
     */
//  @Bean
//  public FilterRegistrationBean filterRegistrationBean() {
//      FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
//      filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
//      //  该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理  
//      filterRegistration.addInitParameter("targetFilterLifecycle", "true");
//      filterRegistration.setEnabled(true);
//      filterRegistration.addUrlPatterns("/*");// 可以自己灵活的定义很多,避免一些根本不需要被Shiro处理的请求被包含进来
//      return filterRegistration;
//  }

    //Filter工厂,设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
 
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 拦截器,必须用LinkedHashMap添加拦截规则
        Map filterChainDefinitionMap = new LinkedHashMap();
        // 设置login URL
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/LoginSuccess.action");
        // 未授权的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized.action");
        // src="jquery/jquery-3.2.1.min.js" 生效
        filterChainDefinitionMap.put("/jquery/*", "anon");
        // 设置登录的URL为匿名访问,因为一开始没有用户验证
        filterChainDefinitionMap.put("/login.action", "anon");
        
        filterChainDefinitionMap.put("/Exception.class", "anon");
        // 我写的url一般都是xxx.action,根据你的情况自己修改
        filterChainDefinitionMap.put("/*.action", "authc");
        // 退出系统的过滤器
        filterChainDefinitionMap.put("/logout", "logout");
        // 现在资源的角色
        filterChainDefinitionMap.put("/admin.html", "roles[admin]");
        // filterChainDefinitionMap.put("/user.html", "roles[user]");
        // 最后一班都,固定格式
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
 
    /*
     * 开启shiro aop注解支持 使用代理方式;所以需要开启代码支持;
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
            DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new 
        AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
 
    /**
     * DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }
 
}

Shiro 的默认Filter工厂 对应的类

 Filter名称  类路径(点击可以进入官方介绍,强烈建议看看 )
 anon  org.apache.shiro.web.filter.authc.AnonymousFilter
 authc  org.apache.shiro.web.filter.authc.FormAuthenticationFilter
 authcBasic  org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
 logout  org.apache.shiro.web.filter.authc.LogoutFilter
 noSessionCreation  org.apache.shiro.web.filter.session.NoSessionCreationFilter
 perms  org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
 port  org.apache.shiro.web.filter.authz.PortFilter
 rest  org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
 roles  org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
 ssl  org.apache.shiro.web.filter.authz.SslFilter
 user  org.apache.shiro.web.filter.authc.UserFilter

 3.自定义Realm类

public class MyShiroRealm extends AuthorizingRealm {
 
	/**
	 * 认证(验证当前用户信息)
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 
		// 将AuthenticationToken强转为AuthenticationToken对象
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
 
		// 获得从表单传过来的用户名
		String username = upToken.getUsername();
 
		// 从数据库查看是否存在用户
		UserService userService = new UserService();
 
		// 如果用户不存在,抛此异常
		if (!userService.selectUsername(username)) {
			throw new UnknownAccountException("无此用户名!");
		}
 
		// 认证的实体信息,可以是username,也可以是用户的实体类对象,这里用的用户名
		Object principal = username;
		// 从数据库中查询的密码
		Object credentials = userService.selectPassword(username);
		// 颜值加密的颜,可以用用户名
		ByteSource credentialsSalt = ByteSource.Util.bytes(username);
		// 当前realm对象的名称,调用分类的getName()
		String realmName = this.getName();
 
		// 创建SimpleAuthenticationInfo对象,并且把username和password等信息封装到里面
		// 用户密码的比对是Shiro帮我们完成的
		SimpleAuthenticationInfo info = null;
		info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
 
		return info;
	}
 
	// 授权(验证权限时调用)
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
 
		// User user=(User)
		// principals.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
		// System.out.println("在MyShiroRealm中AuthorizationInfo(授权)方法中从session中获取的user对象:"+user);
 
		// 从PrincipalCollection中获得用户信息
		Object principal = principals.getPrimaryPrincipal();
		System.out.println("ShiroRealm  AuthorizationInfo:" + principal.toString());
 
		// 根据用户名来查询数据库赋予用户角色,权限(查数据库)
		Set roles = new HashSet<>();
		Set permissions = new HashSet<>();
		roles.add("user");
		permissions.add("user:query");
		if ("admin".equals(principal)) {
			roles.add("admin");
			permissions.add("admin:query");
		}
 
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
		//天加权限
		info.setStringPermissions(permissions);
		return info;
		// return null;
	}
 
}
  • doGetAuthenticationInfo执行时机如下

(1).当调用Subject currentUser = SecurityUtils.getSubject();

currentUser.login(token);

  • doGetAuthorizationInfo执行时机有三个,如下:

​​​​​​​(1).subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什么角色或者是否有什么权限的时候;

​​​​​​​(2).@RequiresRoles("admin") :在方法上加注解的时候;

​​​​​​​(3).[@shiro.hasPermission name = "admin"][/@shiro.hasPermission]:在页面上加shiro标签的时候,即进这个页面的时候扫描到有这个标签的时候。

转载于:https://my.oschina.net/warm6Y/blog/2994224

你可能感兴趣的:(SpringBoot整合Shiro配置详解)