本文将介绍shiro基本概念与安全框架组件,不会过多分析源码等,重在使用。
Shiro本身不会去维护 “用户”、维护权限;安全框架组件是根据shiro相应的接口实现的一套权限控制。

shiro 介绍

Apache Shiro是一个强大且易用的Java安全框架,旨在简化身份验证和授权。目前,使用Apache Shiro的人越来越多。

基本概念

Shiro有三个主要的概念,Subject、SecurityManager 和Realms,下图是这三个组件的交互关系。

  • Subject
    主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

  • SecurityManager
    安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;
    通常情况下,一旦SecurityManager和它的内部各个组件被配置好之后就不会再用到,开发者通常是查看Subject 的API。

  • Realms
    Realms在Shiro和用户的应用程序数据之间扮演着桥梁和连接器的作用。当需要验证或者授权的时候,Shiro从一个或者多个配置的Realms中查找。
    域,Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;这种情况下,Realm是一个安全的DAO,它封装了具体数据库连接的细节,当Shiro需要的时候为Shiro提供需要的数据。当配置Shiro的时候,必须配置至少一个Realm来验证和授权。SecurityManager 可以配置多个Realm,至少需要一个。
    Shiro提供了即用的Realm用来连接到各种安全的数据源,像LDAP, 关系型数据库(JDBC), 文本配置的INI和properties文件等。 用户可以插入自己的Realm 实现,如果默认的Realm 不能满足需求的话。

架构介绍

下图是Shiro的核心架构

  • Subject (org.apache.shiro.subject.Subject)
    与软件交互的具体的安全视图实体(可以是用户,第三方服务,定时任务等)

  • SecurityManager (org.apache.shiro.mgt.SecurityManager)
    Shiro的心脏,协调其他被管理的组件,以确保他们有条不紊地工作。

  • Authenticator (org.apache.shiro.authc.Authenticator)
    认证器,负责主体认证的,这是一个扩展点,如果用户觉得Shiro默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;

  • Authentication Strategy (org.apache.shiro.authc.pam.AuthenticationStrategy)
    当配置了不止一个Realm的时候,AuthenticationStrategy 将会和Realm进行协调来确定哪一个用来验证。

  • Authorizer (org.apache.shiro.authz.Authorizer)
    (授权器,或者访问控制器)Authorizer 用来验证用户的权限,用来验证用户是否被允许做某件事情。

  • SessionManager (org.apache.shiro.session.mgt.SessionManager)
    管理Session的,在任何环境中都可以,即使没有web容器。默认情况下,Shiro将会使用一个已经存在的session机制,如果没有session,它讲使用自己内置的企业级session管理器来提供。SessionDAO 允许任何的数据源用来做持久化session。

  • SessionDAO (org.apache.shiro.session.mgt.eis.SessionDAO)
    SessionDAO 执行Session持久化(CRUD)操作,允许任何能存储数据的都可以被当作Session Management 的基础设计。

  • CacheManager (org.apache.shiro.cache.CacheManager)
    CacheManager 是用来创建和管理缓存的。任何开源的或者企业级缓存产品都可以被Shiro用作提供快速和高效的用户体验。

  • Cryptography (org.apache.shiro.crypto.*)
    加密体系,Shiro的加密包,包含了方便使用和易于理解的加密算法。

  • Realms (org.apache.shiro.realm.Realm)
    Realms在Shiro和用户的应用程序之间扮演着桥梁和连接器的作用。

安全框架组件

安全框架组件根据现有业务分为两大版本: 项目版本( proj-sys-security 2.5.0-SNAPSHOT)、平台版本(upcloud-security 2.3.0-SNAPSHOT)。
项目版本依赖相对较少,目前无session集群及单点登录功能。

功能 项目版本 2.5 平台版本 2.3
用户管理、角色管理、权限管理、权限控制
登录多次尝试,则需输入验证码
重启应用session 保持
后台在线用户管理 ,采用异步刷新至DB(upcloud-framework.scheduler 模块),可剔除当前登录用户
根据标签自动扫描并注册操作权限
session 集群
单点登录

✘ 表示当前版本不提供, ✔ 提供此功能

项目版 (proj-sys-security 2.5.0)

svn地址:http://ip/svn/upcloud-sys/branches/upcloud-sys-pro-2.1.0

项目权限代码将在此拷贝。推出新版本后会定时将此版本的相关代码移植至代码生成器模板中。
proj-sys-parent 分为四个模块:

  • proj-sys-api : api接口及权限标签
  • proj-sys-core : 权限实现核心代码
  • proj-sys-security : 权限安全控制
  • proj-sys-web : 权限web页面代码

依赖

  • shiro 1.2.4
  • shiro-ehcache shiro-spring 1.2.4
  • spring 4.1.9.RELEASE
  • upcloud-framework 2.5.0-SNAPSHOT
  • mysql: sys_init_sql.sql

使用

  • xxx-core pom.xml 引入如下配置:

    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.up72</groupId>
    <artifactId>proj-sys-core</artifactId>
    <version>$proj.sys.version</version>
    </dependency>
  • xxx-web spring-bean-web.xml 引入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <import resource="spring-db.xml"></import>
    <import resource="classpath*:META-INF/sys/spring/spring-mybatis.xml"></import>
    <import resource="classpath*:META-INF/sys/spring/spring-resource.xml"></import>
    <!-- 权限控制配置 -->
    <import resource="spring-shiro.xml"></import>
    <!-- 验证配置 -->
    <import resource="spring-validator.xml"></import>
    <!-- spring相关bean 配置 -->
    <import resource="spring-jsp.xml"></import>
  • xxx-web proj-sys-web/webapp/jsp 目录文件拷贝至xxx-web目录

spring-shiro.xml 介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
default-lazy-init="false">
<!-- 提供数据库jdbc操作 -->
<bean id="jdbcTemplate" class="com.up72.framework.jdbc.JdbcTemplate" >
<property name="dataSource" ref="dataSource"></property>
<property name="dialect">
<bean class="com.up72.framework.jdbc.dialect.MySQLDialect"></bean>
</property>
</bean>
<!-- 在线用户 sql
create table `sys_user_session`(
`id` varchar(100) not null,
`username` varchar(100),
`host` varchar(100),
`system_host` varchar(100),
`user_agent` varchar(200),
`start_timestsamp` timestamp default 0 ,
`last_access_time` timestamp default 0 ,
`timeout` bigint ,
`session` mediumtext,
constraint `pk_sys_user_online` primary key(`id`),
index `idx_sys_user_session_username` (`username`),
index `idx_sys_user_session_host` (`host`),
index `idx_sys_user_session_system_host` (`system_host`),
index `idx_sys_user_session_start_timestsamp` (`start_timestsamp`),
index `idx_sys_user_session_last_access_time` (`last_access_time`),
index `idx_sys_user_session_user_agent` (`user_agent`)
) charset=utf8 ENGINE=InnoDB;
-->
<!-- 添加用户跟踪器 (10条 or 1分钟 触发) -->
<bean id="onlineInserSqlTracker" class="com.up72.framework.scheduler.SchedulerTracker" destroy-method="close">
<constructor-arg index="0" name="name" value="onlineInserSql"></constructor-arg>
<constructor-arg index="1" name="count" value="10"></constructor-arg>
<constructor-arg index="2" name="time" value="60000"></constructor-arg>
<property name="service" >
<bean class="com.up72.security.shiro.session.mgt.service.SchedulerExecute">
<property name="userSessionService" ref="userSessionService"></property>
</bean>
</property>
</bean>
<!-- 更新用户状态跟踪器 (10条 or 2分钟 触发) -->
<bean id="onlineUpdateSqlTracker" class="com.up72.framework.scheduler.SchedulerTracker" destroy-method="close">
<constructor-arg index="0" name="name" value="onlineUpdateSql"></constructor-arg>
<constructor-arg index="1" name="count" value="100"></constructor-arg>
<constructor-arg index="2" name="time" value="120000"></constructor-arg>
<property name="service" >
<bean class="com.up72.security.shiro.session.mgt.service.SchedulerExecute">
<property name="userSessionService" ref="userSessionService"></property>
</bean>
</property>
</bean>
<!-- user session 管理类 -->
<bean id="userSessionService" class="com.up72.security.shiro.session.mgt.service.UserSessionService">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!-- 自定义 shiro realm 实现类 -->
<bean id="dbAuthRealm" class="com.up72.security.shiro.realm.DbAuthRealm">
<!--<property name="cacheManager" ref="shiroEhcacheManager"></property>-->
<!--<property name="cachingEnabled" value="true"/>-->
<!--<property name="authenticationCachingEnabled" value="true"/>-->
<!--<property name="authenticationCacheName" value="authenticationCache"/>-->
<!--<property name="authorizationCachingEnabled" value="true"/>-->
<!--<property name="authorizationCacheName" value="authorizationCache"/>-->
</bean>
<!-- 会话ID生成器 -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<!-- 会话Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="upsid"/>
<property name="httpOnly" value="true"/>
<!-- 单位秒 浏览器关闭后销毁 -->
<property name="maxAge" value="-1"/>
</bean>
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe"/>
<property name="httpOnly" value="true"/>
<!-- 单位秒 5*60*24小时 -->
<property name="maxAge" value="2592000"/>
</bean>
<!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<!-- rememberme cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)-->
<property name="cipherKey"
value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<!-- 会话DAO -->
<bean id="sessionDAO" class="com.up72.security.shiro.session.mgt.eis.MyCacheSessionDAO">
<property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
<property name="userSessionService" ref="userSessionService"></property>
</bean>
<!-- 会话验证调度器 -->
<bean id="sessionValidationScheduler" class="com.up72.security.shiro.session.mgt.scheduler.MySessionValidationScheduler">
<!-- 毫秒 30分钟 -->
<property name="interval" value="1800000"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>
<!-- 会话管理器 -->
<bean id="sessionManager" class="com.up72.security.shiro.web.session.mgt.WebSessionManager">
<!-- 毫秒 30分钟 -->
<property name="globalSessionTimeout" value="1800000"/>
<property name="deleteInvalidSessions" value="true"/>
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
<property name="sessionDAO" ref="sessionDAO"/>
<property name="sessionIdCookieEnabled" value="true"/>
<property name="sessionIdCookie" ref="sessionIdCookie"/>
<property name="sessionFactory" ref="onlieSessionFactory"></property>
<property name="userSessionService" ref="userSessionService"></property>
</bean>
<bean id="onlieSessionFactory" class="com.up72.security.shiro.session.mgt.OnlineSessionFactory"></bean>
<bean id="myFormAuthenticationFilter" class="com.up72.security.shiro.web.filter.authc.MyFormAuthenticationFilter" />
<!-- Shiro's main business-tier object for web-enabled applications 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="dbAuthRealm" />
<property name="cacheManager" ref="shiroEhcacheManager" />
<property name="sessionManager" ref="sessionManager"/>
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="filters">
<util:map>
<entry key="authc" value-ref="myFormAuthenticationFilter"/>
</util:map>
</property>
<property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource"/>
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/jsp/admin/login/login.jsp" />
<property name="successUrl" value="/index.jsp" />
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
</bean>
<bean id="chainDefinitionSectionMetaSource" class="com.up72.security.shiro.ChainDefinitionSectionMetaSource">
<property name="filterChainDefinitions">
<value>
/favicon.ico anon
/scripts/** anon
/adminStyles/** anon
/jsp/admin/login/** = anon
/jsp/menu/** = authc
/jsp/sysConfig/** = authc
/jsp/admin/** = authc
/common/error.jsp = anon
</value>
</property>
</bean>
<!-- 用户授权信息Cache, 采用EhCache -->
<bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
</bean>
<!-- securityManager -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager" />
<property name="arguments" ref="securityManager" />
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>

平台版(待续)

。。。

本文地址: http://blog.up72.cn/2016/08/02/security component for shiro/