本文将介绍shiro的springboot集成,基于官网的指南来做的。虽然比较简单,但还是注意一下版本的兼容性问题。
官网指南:https://shiro.apache.org/spring-boot.html
1 引入shiro
本demo使用springboot 2.2.6.RELEASE,shiro 则选择了 1.12.0。
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring-boot-web-starter</artifactId>
  <version>1.12.0</version>
</dependency>
PS:
shiro 的 1.12.0 版本可能无法支持 springboot 3.X 版本(比如:3.1.2)。
其一是因为新版本 AutoConfigurationExcludeFilter 中改成了对 @AutoConfiguration 注解扫描,导致无法正常自动配置。 从 shiro-spring-boot-web-starter 包的 spring.factory 文件中还是用的 EnableAutoConfiguration 注解来进行自动配置。
2 提供一个Realm的实现
be like:
@Bean
public Realm realm(){
    SimpleAccountRealm accountRealm = new SimpleAccountRealm();
    accountRealm.addAccount("admin", "12345", ADMIN, USER);
    accountRealm.addAccount("user", "12345", USER);
    return accountRealm;
}
从上面这个简单的实现,不难看出 Realm 的实现类就是提供用来登录认证的账户信息的。
Realm 有多个实现类,可以挑选合适的,并继承它来做自定义的实现。
可以通过继承 AuthorizingRealm 类来做:
public class AccountRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private UserRoleService userRoleService;
    // 从基础数据存储中检索给定主体的授权信息。从此方法返回实例时,您可能需要考虑使用 SimpleAuthorizationInformation 的实例,因为它适用于大多数情况。
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        ...
    }
    // 从特定于实现的数据源(RDBMS、LDAP 等)中检索给定身份验证令牌的身份验证数据。
    // 对于大多数数据源,这意味着只需为关联的主体/用户“提取”身份验证数据,仅此而已,其余的让 Shiro 完成。但是在某些系统中,除了检索数据之外,这种方法实际上还可以执行特定于 EIS 的登录逻辑 - 这取决于 Realm 的实现。
    // null 返回值表示任何帐户都不能与指定的令牌关联。
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        ...
    }
}
3 提供一个 ShiroFilterChainDefinition
为了校验不同的请求路径要求的不同权限,需要用 ShiroFilterChainDefinition 类来定义好(映射)应用中任何特定的请求路径(path)的权限要求。
3.1 直接定义路径的角色&权限校验
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
    DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
    // logged in users with the 'admin' role
    // 要求登录用户有 admin 角色的路径
    chainDefinition.addPathDefinition("/admin/**", "authc, roles[admin]");
    // logged in users with the 'document:read' permission
    // 要求登录用户有 document:read 这个权限的路径
    chainDefinition.addPathDefinition("/docs/**", "authc, perms[document:read]");
    // all other paths require a logged in user
    // 其它所有路径都要求用户要登录
    chainDefinition.addPathDefinition("/**", "authc");
    return chainDefinition;
}
3.2 通过 shiro 注解
@RequiresPermissions--权限要求注解:
@RequiresPermissions("document:read")
public void readDocument() {
    ...
}
@RequiresRoles--角色要求注解:
@Controller
public class AccountInfoController {
    @RequiresRoles("admin")
    @RequestMapping("/admin/config")
    public String adminConfig(Model model) {
        return "view";
    }
}
@RequiresPermissions 和 @RequiresRoles 这两个注解即可以加在方法上面,也可以直接加到类上面。
此外,ShiroFilterChainDefinition 这个bean对象还是需要的:
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
    DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
    chainDefinition.addPathDefinition("/**", "anon"); // all paths are managed via annotations【所有路径都通过注解进行管理】
    // or allow basic authentication, but NOT require it.【或允许基本身份验证,但不需要它】
    // chainDefinition.addPathDefinition("/**", "authcBasic[permissive]");
    return chainDefinition;
}
4 缓存管理器 CacheManager
需要启用自定义的缓存,那只需要提供一个缓存管理器的bean:
@Bean
protected CacheManager cacheManager() {
    return new MemoryConstrainedCacheManager();
}
如果要用 EhCache 或者 redis 等等,需要引用对应的 jar 包依赖,be like:
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>${shiro}</version>
</dependency>
@Bean
public CacheManager shiroCacheManager(net.sf.ehcache.CacheManager cacheManager) {
    EhCacheManager ehCacheManager = new EhCacheManager();
    ehCacheManager.setCacheManager(cacheManager);
    return ehCacheManager;
}
5 常见配置
| Key | Default Value | Description | 
|---|---|---|
| shiro.enabled | true | 开启shiro的spring模块 | 
| shiro.web.enabled | true | 开启shiro的spring web模块 | 
| shiro.annotations.enabled | true | 开启spring支持shiro注解 | 
| shiro.userNativeSessionManager | false | 如果启用,Shiro将管理HTTP会话而不是容器 | 
| shiro.sessionManager.cookie.name | JSESSIONID | Session cookie 的名称 | 
| shiro.sessionManager.cookie.maxAge | -1 | Session cookie 的最大年龄 | 
| shiro.rememberMeManager.cookie.name | rememberMe | RememberMe cookie 的名称 | 
| shiro.rememberMeManager.cookie.maxAge | one year | RememberMe cookie 的最大年龄 | 
| shiro.loginUrl | /login.jsp | 登录页 | 
| shiro.successUrl | / | 用户登录后的默认登录页面(如果在当前会话中找不到替代页面) | 
| shiro.unauthorizedUrl | null | 如果用户未经授权,则重定向到的页面(403页面) | 
小结:
- 引入jar包依赖
- 提供一个Realm接口的实现--认证用的
- 提供 ShiroFilterChainDefinition 定义--对路径管控的定义
- 缓存管理器--用户登录信息的保存
springboot 3.x 自动配置类的扫描
与 spring.factories 的方式类似,需要在 META-INF 目录下创建 spring 目录,在里面创建一个文件名为: org.springframework.boot.autoconfigure.AutoConfiguration.imports
在文件内直接配置上要相关的配置类,be like:
org.apache.shiro.spring.boot.autoconfigure.ShiroBeanAutoConfiguration
org.apache.shiro.spring.boot.autoconfigure.ShiroAutoConfiguration
org.apache.shiro.spring.boot.autoconfigure.ShiroAnnotationProcessorAutoConfiguration
【由于shiro目前最新版本1.12.0并不支持springboot 3.x,所以自动配置这块还得自己来。此外,还是由于兼容性问题,最后我没有在项目中升级到shiro最新版本,而是继续使用目前的 1.4.0 版本(能平稳运行。。。)】
注意:本文归作者所有,未经作者允许,不得转载
