IT小栈

  • 主页
  • Java基础
  • RocketMQ
  • Kafka
  • Redis
  • Shiro
  • Spring
  • Spring Boot
  • Spring Cloud
  • 资料链接
  • 关于
所有文章 友链

IT小栈

  • 主页
  • Java基础
  • RocketMQ
  • Kafka
  • Redis
  • Shiro
  • Spring
  • Spring Boot
  • Spring Cloud
  • 资料链接
  • 关于

Shiro简单使用

2019-07-27

上一章节中我们简单的介绍了Shiro,本节我们将介绍其在项目中的使用。介绍其在项目中如何配置及相关的作用是什么。

1、入口拦截器介绍

入口配置拦截器,Shiro是通过拦截所有的请求的URL对其进行权限控制的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!— shiro的过滤器,DelegatingFilterProxy 通过代理模式将spring容器中的bean和filter关联-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
<!— 设置true由servlet容器控制filter的生命周期 -->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!— 设置spring容器filter的bean id 如果不设置则找与filter-name一致的bean-->
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shiroFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

这里配置的是DelegatingFilterProxy,顾名思义啊,可以看出这是个代理类,那么代理的是哪个具体对象呢?

代理的对象我们配置在applicationContext.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
<!-- Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/a/login"/>
<property name="filters">
<util:map>
<entry key="forceLogout" value-ref="forceLogoutFilter"/>
<entry key="authc" value-ref="formAuthenticationFilter"/>
<entry key="logout" value-ref="logoutFilter" />
<entry key="slog" value-ref="slogFilter" />
<entry key="userAccess" value-ref="userAccessFilter"/>
</util:map>
</property>
<!--anon匿名访问,authc身份验证后访问,roles指定角色授权访问,perms指定类似user:create权限访问-->
<property name="filterChainDefinitions">
<value>
/static/** = anon
${adminPath}/config/policecheck/level = anon
${adminPath}/myapply/** = anon
${adminPath}/register = anon,slog
${restPath}/** = anon,userAccess,slog
${frontPath}/** = anon,forceLogout,slog
${adminPath}/login = authc,slog
${adminPath}/logout = logout,slog
${adminPath}/** = user,perms,roles,forceLogout,slog
</value>
</property>
</bean>

我们发现了其核心类securityManager

2、核心类安全管理器SecurityManager

1
2
3
4
5
6
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm"/>
<property name="sessionManager" ref="sessionManager"/>
<property name="cacheManager" ref="cacheManager"/>
</bean>

2.1、Realm实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Realm实现 -->
<bean id="userRealm" class="cn.iutils.common.filter.realm.UserRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
<property name="cachingEnabled" value="true"/>
<property name="authenticationCachingEnabled" value="true"/>
<property name="authenticationCacheName"value="authenCache"/>
<property name="authorizationCachingEnabled" value="true"/>
<property name="authorizationCacheName" value="authorCache"/>
</bean>
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher" class="cn.iutils.common.filter.RetryLimitHashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5"/>
<property name="hashIterations" value="2"/>
<property name="storedCredentialsHexEncoded" value="true"/>
</bean>

用户需要自己实现Realm实现其认证和授权相关的操作。

参数名 参数说明
cachingEnabled 缓存是否开启 默认false
authenticationCachingEnabled 认证缓存是否开启 默认false
authenticationCacheName 认证缓存名称
authorizationCachingEnabled 授权缓存是否开启 默认false
authorizationCacheName 授权缓存名称

Realm在验证用户身份的时候,要进行密码匹配。最简单的情况就是明文直接匹配,然后就是加密匹配,这里的匹配工作则就是交给CredentialsMatcher来完成的。

参数名 参数解释 参数数据类型
algorithmName 加密类型[MD5、Md2、Sha1、Sha256等] String
hashIterations 对目标对象加密次数,次数越多可靠性越高。同时越复杂 int
storedCredentialsHexEncoded 指定Hash散列值使用Hex加密存储。value=”false”表明hash散列值用用Base64-encoded存储 boolean

2.2、会话管理器

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
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- session的失效时长,单位毫秒 -->
<property name="globalSessionTimeout" value="1800000"/>
<!-- 删除失效的会话 -->
<property name="deleteInvalidSessions" value="true"/>
<!-- 设置SessionDAO用于会话的CRUD,即DAO(Data Access Object)-->
<property name="sessionDAO" ref="sessionDAO"/>
<!-- 启用Cookie -->
<property name="sessionIdCookieEnabled" value="true"/>
<!-- 配置Cookie -->
<property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>
<!-- sessionDAO -->
<bean id="sessionDAO" class="cn.iutils.sys.dao.IDBSessionDAO">
<property name="activeSessionsCacheName" value=" shiro-activeSessionCache"/>
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
</bean>
<!-- 会话ID生成器 -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>

<!-- 会话Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- 设置Cookie名字, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! -->
<property name="name" value="gumx.session.id"/>
<!-- 如果设置为true,则客户端不会暴露给客户端脚本代码,使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击;此特性需要实现了Servlet 2.5 MR6及以上版本的规范的Servlet容器支持 -->
<property name="httpOnly" value="true"/>
<!-- 设置Cookie的过期时间,秒为单位,默认-1表示关闭浏览器时过期Cookie -->
<property name="maxAge" value="1800"/>
</bean>

在Servlet容器中,默认使用JSESSIONID Cookie维护会话,且会话默认是跟容器绑定的;在某些情况下可能需要使用自己的会话机制,此时我们可以使用DefaultWebSessionManager来维护会话。

2.3、缓存管理器

1
2
3
4
<!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache/ehcache.xml"/>
</bean>

缓存处理器 shiro默认实现了Ehcache缓存只需要配置相应的参数即可

3、Realm实现认证授权(需要编码实现)

项目中集成Shiro权限框架的唯一需要编码的地方就是Realm来实现认证授权操作。

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
public class UserRealm extends AuthorizingRealm {

@Autowired
private UserService userService;

/**
* 授权 每次点击都会进行验证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(userService.findRoles());
authorizationInfo.setStringPermissions(userService
.findPermissions());
return authorizationInfo;
}

/**
* 登录认证 登录时验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userService.getUserByUserName(username);
if (user == null) {
throw new UnknownAccountException();// 没找到帐号
}
if (Boolean.TRUE.equals(user.getLocked())) {
throw new LockedAccountException(); // 帐号锁定
}

List<Object> principals=new ArrayList<Object>();
principals.add(user.getUsername());
principals.add(user);
// 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
principals, // 用户名+user对象
user.getPassword(), // 密码
new MySimpleByteSource(user.getCredentialsSalt()),// salt=username+salt
getName() // realm name
);
return authenticationInfo;
}

@Override
public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
super.clearCachedAuthorizationInfo(principals);
}
@Override
public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
super.clearCachedAuthenticationInfo(principals);
}
@Override
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
}
}

实现凭证代码

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
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

private Cache<String, AtomicInteger> passwordRetryCache;

/**
* 初始化密码缓存
* @param cacheManager
*/
public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
passwordRetryCache = cacheManager.getCache(JConfig.getConfig("iutils.passwordRetry.cache"));
}

@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
String username = (String)token.getPrincipal();
//错误次数累加 10分钟后清除
AtomicInteger retryCount = passwordRetryCache.get(username);
if(retryCount == null) {
retryCount = new AtomicInteger(0);
passwordRetryCache.put(username, retryCount);
}
if(retryCount.incrementAndGet() > 5) {
//规定时间内超出错误次数
throw new ExcessiveAttemptsException();
}

boolean matches = super.doCredentialsMatch(token, info);
if(matches) {
//匹配正确后,清除错误计数器
passwordRetryCache.remove(username);
}
return matches;
}
}
本文作者: 顾 明 训
本文链接: https://www.itzones.cn/2019/07/27/Shiro简单使用/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!
  • shiro入门
  • shiro

扫一扫,分享到微信

微信分享二维码
Shiro工作原理
Shiro简单介绍
  1. 1. 1、入口拦截器介绍
  2. 2. 2、核心类安全管理器SecurityManager
    1. 2.1. 2.1、Realm实现
    2. 2.2. 2.2、会话管理器
    3. 2.3. 2.3、缓存管理器
  3. 3. 3、Realm实现认证授权(需要编码实现)
© 2020 IT小栈
载入天数...载入时分秒... || 本站总访问量次 || 本站访客数人次
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链

tag:

  • jvm
  • Java基础
  • kafka HW
  • kafka Leader Epoch
  • kafka
  • kafka位移主题
  • kafka位移提交
  • kafka副本机制
  • kafka ISR
  • zookeeper
  • kafka消息丢失
  • kafka日志存储
  • kafka Log Clean
  • kafka Log Compaction
  • kafka消费位移设置
  • kafka Rebalance
  • kafka分区算法
  • kafka生产者拦截器
  • kafka SASL/SCRAM
  • kafka ACL
  • redis
  • redis Ziplist
  • redis Hashtable
  • redis LinkedList
  • redis QuickList
  • redis intset
  • redis String
  • redis SDS
  • redis SkipList
  • redisDb
  • redisServer
  • redis 简介
  • Redis Cluster
  • 主从同步
  • RocketMQ高可用HA
  • 事务消息
  • 内存映射
  • MMAP
  • 同步刷盘
  • 异步刷盘
  • 消息存储文件
  • RocketMQ安装
  • 延迟消息
  • RocketMQ入门
  • 推拉模式
  • PushConsumer
  • 消费结果处理
  • rebalance
  • RocketMQ权限控制
  • RocketMQ ACL
  • 消息过滤
  • 消息重试
  • 消费位置
  • 集群消费
  • 广播消费
  • 运维命令
  • shiro源码分析
  • shiro入门
  • IOC和DI
  • Spring创建Bean
  • Bean生命周期
  • Sping属性注入
  • 异常
  • SpringMVC
  • springCloud
  • Eureka

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 我的OSCHINA
  • 我的CSDN
  • 我的GITHUB
  • 一生太水