Shiro框架基础

ApacheShiro是Java 的一个安全(权限)框架。

Shiro可以完成:认证、授权、加密、会话管理、与Web 集成、缓存等。

基本功能

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

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

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

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

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

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

Concurrency:Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权自传过;

Testing:提供测试支持;

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

Remember Me:记住功能,即一次登录后,下次再来的话不用登录了

Shiro架构

 

Subject:应用代码直接交互的对象是Subject,Subject 代表了当前“用户”,与Subject 的所有交互都会委托给SecurityManager,SecurityManager才是实际的执行者;

SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;管理着所有Subject,负责与Shiro的其他组件进行交互。

Realm:Shiro从Realm 获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么需要从Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm 得到用户相应的角色/权限进行验证用户是否能进行操作。

CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能

shiro中默认的过滤器

URL 匹配模式

url模式使用Ant 风格模式

Ant 路径通配符支持?、*、**,注意通配符匹配不包括目录分隔符/

?:匹配单字符,如/admin? 将匹配/admin1,但不匹配/admin 或/admin/;

*:匹配零个或多个字符串,如/admin 将匹配/admin、/admin123,但不匹配/admin/1;

**:匹配路径中的零个或多个路径,如/admin/** 将匹配/admin/a 或/admin/a/b

URL 匹配顺序

URL 权限采取第一次匹配优先的方式,即从头开始使用第一个匹配的url模式对应的拦截器链。

例如:

/bb/**=filter1

/bb/aa=filter2

/**=filter3

当访问uri是/bb/aa时,将进入filter1拦截器

Authentication(身份认证)

用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份

principals:身份,即主体的标识属性,可以是任何属性。如用户名、邮箱等,唯一即可。一 个主体可以有多个principals,但只有一个Primary principals,一般是用户名/邮箱/ 手机号。

credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。

Authenticator

SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm 进行验证,验证规则通过AuthenticationStrategy接口指定

AuthenticationStrategy

FirstSuccessfulStrategy:只要有一个Realm 验证成功即可,只返回第一个Realm 身份验证成功的认证信息,其他的忽略;

AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,将返回所有Realm身份验证成功的认证信息;

AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。

ModularRealmAuthenticator默认是AtLeastOneSuccessfulStrategy策略

 

Permissions

规则:资源标识符:操作:对象实例ID。

默认支持通配符权限字符串,: 表示资源/操作/实例的分割;, 表示操作的分割,* 表示任意资源/操作/实例。

多层次管理:

单值:user:query、user:edit

多值:user:query, edit

泛值:user:*

权限注解

@RequiresAuthentication:表示当前Subject已经通过login 进行了身份验证;即Subject. isAuthenticated() 返回true

 

@RequiresUser:表示当前Subject 已经身份验证或者通过记住我登录的。

@RequiresGuest:表示当前Subject没有身份验证或通过记住我登录过,即是游客身份。

@RequiresRoles(value={“admin”, “user”}, logical= Logical.AND):表示当前Subject 需要角色admin 和user

@RequiresPermissions(value={“user:a”, “user:b”}, logical= Logical.OR):表示当前Subject 需要权限user:a或user:b。

会话相关的API

Subject.getSession():即可获取会话;其等价于Subject.getSession(true),即如果当前没有创建Session 对象会创建一个;Subject.getSession(false),如果当前没有创建Session 则返回null

session.getId():获取当前会话的唯一标识

session.getHost():获取当前Subject的主机地址

session.getTimeout() & session.setTimeout(毫秒):获取/设置当前Session的过期时间

session.getStartTimestamp() & session.getLastAccessTime():获取会话的启动时间及最后访问时间.(JavaSE应用需要自己定期调用session.touch() 去更新最后访问时间;如果是Web 应用,每次进入ShiroFilter都会自动调用session.touch() 来更新最后访问时间。)

session.touch() & session.stop():更新会话最后访问时间及销毁会话;当Subject.logout()时会自动调用stop 方法来销毁会话。如果在web中,调用HttpSession. invalidate() 也会自动调用ShiroSession.stop方法进行销毁Shiro的会话

SessionDao

AbstractSessionDAO提供了SessionDAO的基础实现,如生成会话ID等

CachingSessionDAO提供了对开发者透明的会话缓存的功能,需要设置相应的CacheManager

MemorySessionDAO直接在内存中进行会话维护

EnterpriseCacheSessionDAO提供了缓存功能的会话维护,默认情况下使用MapCache实现,内部使用ConcurrentHashMap保存缓存的会话。

会话验证

Shiro提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话

Shiro提供了会话验证调度器SessionValidationScheduler

Shiro也提供了使用Quartz会话验证调度器:QuartzSessionValidationScheduler

缓存

Shiro内部相应的组件(DefaultSecurityManager)会自动检测相应的对象(如Realm)是否实现了CacheManagerAware并自动注入相应的CacheManager。

Realm 缓存

Shiro提供了CachingRealm,其实现了CacheManagerAware接口,提供了缓存的一些基础实现;

AuthenticatingRealm及AuthorizingRealm也分别提供了对AuthenticationInfo和AuthorizationInfo信息的缓存。

Session 缓存

SecurityManager实现了SessionSecurityManager,其会判断SessionManager是否实现了CacheManagerAware接口,如果实现了会把CacheManager设置给它。

SessionManager也会判断相应的SessionDAO(如继承自CachingSessionDAO)是否实现了CacheManagerAware,如果实现了会把CacheManager设置给它

设置了缓存的SessionManager,查询时会先查缓存,如果找不到才查数据库。

HelloWord:

public static void main(String[] args) {
		// 初始化配置文件
		Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
		SecurityManager securityManager = factory.getInstance();
		// 设置安全管理器
		SecurityUtils.setSecurityManager(securityManager);
		// 获取当前的 Subject. 调用 SecurityUtils.getSubject();
		Subject currentUser = SecurityUtils.getSubject();
		// 获取 Session: Subject#getSession()
		Session session = currentUser.getSession();
		session.setAttribute("someKey", "aValue");
		String value = (String) session.getAttribute("someKey");
		if (value.equals("aValue")) {
			log.info("---> Retrieved the correct value! [" + value + "]");
		}

		// 测试当前的用户是否已经被认证. 即是否已经登录.
		if (!currentUser.isAuthenticated()) {
			// 把用户名和密码封装为 UsernamePasswordToken 对象
			UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
			// 记住
			token.setRememberMe(true);
			try {
				// 执行登录.
				currentUser.login(token);
			} catch (UnknownAccountException uae) {// 若没有指定的账户, 则 shiro将会抛出 UnknownAccountException异常.
				log.info("----> There is no user with username of " + token.getPrincipal());
				return;
			} catch (IncorrectCredentialsException ice) {// 若账户存在, 但密码不匹配, 则 shiro 会抛出 IncorrectCredentialsException 异常。
				log.info("----> Password for account " + token.getPrincipal() + " was incorrect!");
				return;
			} catch (LockedAccountException lae) {// 用户被锁定的异常 LockedAccountException
				log.info("The account for username " + token.getPrincipal() + " is locked.  "
						+ "Please contact your administrator to unlock it.");
			} catch (AuthenticationException ae) {// 所有认证时异常的父类.
				// unexpected condition? error?
			}
		}
		log.info("----> User [" + currentUser.getPrincipal() + "] logged in successfully.");
		// 测试是否有某一个角色. 调用 Subject 的 hasRole 方法.
		if (currentUser.hasRole("schwartz")) {
			log.info("----> May the Schwartz be with you!");
		} else {
			log.info("----> Hello, mere mortal.");
			return;
		}
		// 测试用户是否具备某一个行为. 调用 Subject 的 isPermitted() 方法。
		if (currentUser.isPermitted("lightsaber:weild")) {
			log.info("----> You may use a lightsaber ring.  Use it wisely.");
		} else {
			log.info("Sorry, lightsaber rings are for schwartz masters only.");
		}
		// 测试用户是否具备某一个行为.
		if (currentUser.isPermitted("user:delete:zhangsan")) {
			log.info("----> You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  "
					+ "Here are the keys - have fun!");
		} else {
			log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
		}
		// 执行登出. 调用 Subject 的 Logout() 方法.
		System.out.println("---->" + currentUser.isAuthenticated());
		currentUser.logout();
		System.out.println("---->" + currentUser.isAuthenticated());
		System.exit(0);
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值