认证就是用户确认身份的过程,确认登录的用户身份能够操作的内容。
使用shiro认证分为以下几个步骤:
1,得到主体的认证和凭据。
// let's login the current user so we can check against roles and permissions: if (!currentUser.isAuthenticated()) { UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); token.setRememberMe(true);
2,提交认证和凭据给身份验证系统。
Subject currentUser = SecurityUtils.getSubject(); currentUser.login(token);
3,判断是否允许访问,重试认证或者阻止访问。
try { currentUser.login(token); } catch (UnknownAccountException uae) { log.info("There is no user with username of " + token.getPrincipal()); } catch (IncorrectCredentialsException ice) { log.info("Password for account " + token.getPrincipal() + " was incorrect!"); } catch (LockedAccountException lae) { log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } // ... catch more exceptions here (maybe custom ones specific to your application? catch (AuthenticationException ae) { //unexpected condition? error? }
其中Remember Me的功能包括两个方法,一个是
isRemembered
boolean isRemembered()
非匿名登录的用户可以记住上次使用的主题的信息。
isAuthenticated
boolean isAuthenticated()
在此期间需要使用有效的凭据登录系统,否则值为false.
授权操作
授权的例子就是是否可以访问某个页面,可以操作某个按钮,是否可以编缉对应的数据等。
如何在shiro中使用授权
1,使用编程方式
判断是否有管理员角色
if (currentUser.hasRole("admin")) {
判断用户是否有打印的权限
Permission printPermission = new PrinterPermission(“laserjet3000n”,“print”);
If (currentUser.isPermitted(printPermission)) { //do one thing (show the print button?) } else { //don’t show the button? }
也可以使用字符串的方式验证
String perm = “printer:print:laserjet4400n”; if(currentUser.isPermitted(perm)){ //show the print button? } else { //don’t show the button? }
2,使用注释方式
判断用户是否有 创建账户权限
//Will throw an AuthorizationException if none //of the caller’s roles imply the Account //'create' permission\u000B @RequiresPermissions(“account:create”) public void openAccount( Account acct ) { //create the account }
判断用户角色,如果符合角色,可以使用对应方法
//Throws an AuthorizationException if the caller //doesn’t have the ‘teller’ role: @RequiresRoles( “teller” ) public void openAccount( Account acct ) { //do something in here that only a teller //should do }
3,使用jsp taglib
判断用户是否有管理权限
<%@ taglib prefix=“shiro” uri=http://shiro.apache.org/tags %> <html> <body> <shiro:hasPermission name=“users:manage”> <a href=“manageUsers.jsp”> Click here to manage users </a> </shiro:hasPermission> <shiro:lacksPermission name=“users:manage”> No user management for you! </shiro:lacksPermission> </body> </html>
从高的级别来看shiro:
看一下官方的图
应用程序调用subject(主题),主题可以是一个用户也可以是与系统交互的另一个系统,主题绑定shiro的权限管理,SecurityManager(安全管理),它控制与有与主题相关的安全操作。Realm(桥梁)它是安全与数据之间的桥,它封装了比如DAO的配置信息,可以指定连接的数据源,也可使用其它的认证方式,如LDAP等。
然后看一下详细的架构图:
Subject (org.apache.shiro.subject.Subject)
主题:与系统交互的第三方如(用户,cron服务,第三方应用)等。
SecurityManager (org.apache.shiro.mgt.SecurityManager)
shiro系统的核心,协调主题使用的操作,验证,配置等。
Authenticator (org.apache.shiro.authc.Authenticator)
身份验证组件,对企图登录系统的用户进行身份的验证。其中包含一个Authentication Strategy
(org.apache.shiro.authc.pam.AuthenticationStrategy)组件。配置验证成功与失败的条件。
Authorizer (org.apache.shiro.authz.Authorizer)
授权组件,指用户访问特定应用程序的机制。
SessionManager (org.apache.shiro.session.mgt.SessionManager)
管理会话如何创建生命周期。其中包括的sessiondao是管理会议数据的持久操作:SessionDAO (org.apache.shiro.session.mgt.eis.SessionDAO),代表执行sessionManager的CRUD操作。
CacheManager (org.apache.shiro.cache.CacheManager)
缓存管理模块。
Cryptography (org.apache.shiro.crypto.*)
加密模块。
Realms (org.apache.shiro.realm.Realm)
多种方式处理的桥梁。
多种配置方式:
与spring,jboss,guice等进行配置。
1,编程方式配置
例如:
Realm realm = //instantiate or acquire a Realm instance. We'll discuss Realms later. SecurityManager securityManager = new DefaultSecurityManager(realm); //Make the SecurityManager instance available to the entire application via static memory: SecurityUtils.setSecurityManager(securityManager);
2,sessionManager对象图
如果你想使用sessionManager配置自定义的sessionDao信息,进行自定义会话管理
... DefaultSecurityManager securityManager = new DefaultSecurityManager(realm); SessionDAO sessionDAO = new CustomSessionDAO(); ((DefaultSessionManager)securityManager.getSessionManager()).setSessionDAO(sessionDAO); ...
3,INI配置
1) 创建一个INI从SecurityManager
可以从多种方式读取INI配置文件的信息,如文件系统,类路径等
import org.apache.shiro.SecurityUtils; import org.apache.shiro.util.Factory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.config.IniSecurityManagerFactory; ... Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager);
2) 通过Ini实例读取
类似于Properties的方式
import org.apache.shiro.SecurityUtils; import org.apache.shiro.util.Factory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.config.Ini; import org.apache.shiro.config.IniSecurityManagerFactory; ... Ini ini = new Ini(); //populate the Ini instance as necessary ... Factory<SecurityManager> factory = new IniSecurityManagerFactory(ini); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager);
加载之后就可以操作INI的配置了。
4,INI配置
每一个节点都是单独的,不可以重复,注释可以使用#或者;
配置示例
# ======================= # Shiro INI configuration # ======================= [main] # Objects and their properties are defined here, # Such as the securityManager, Realms and anything # else needed to build the SecurityManager [users] # The 'users' section is for simple deployments # when you only need a small number of statically-defined # set of User accounts. [roles] # The 'roles' section is for simple deployments # when you only need a small number of statically-defined # roles. [urls] # The 'urls' section is used for url-based security # in web applications. We'll discuss this section in the # Web documentation
1) [main]
配置sessionManager的实例和它的依赖。
配置示例
[main] sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher myRealm = com.company.security.shiro.DatabaseRealm myRealm.connectionTimeout = 30000 myRealm.username = jsmith myRealm.password = secret myRealm.credentialsMatcher = $sha256Matcher securityManager.sessionManager.globalSessionTimeout = 1800000
定义一个对象
[main] myRealm = com.company.shiro.realm.MyRealm ...
简单的属性设置
... myRealm.connectionTimeout = 30000 myRealm.username = jsmith ...
配置信息将转入到对应的set方法中
... myRealm.setConnectionTimeout(30000); myRealm.setUsername("jsmith"); ...
参考值
你可以使用$符号引用先前定义的一个对象的实例
... sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher ... myRealm.credentialsMatcher = $sha256Matcher ...
嵌套属性
... securityManager.sessionManager.globalSessionTimeout = 1800000 ...
将被注入到下面的程序中
securityManager.getSessionManager().setGlobalSessionTimeout(1800000);
引用其它的属性
sessionListener1 = com.company.my.SessionListenerImplementation ... sessionListener2 = com.company.my.other.SessionListenerImplementation ... securityManager.sessionManager.sessionListeners = $sessionListener1, $sessionListener2
以键值的配置方式
object1 = com.company.some.Class object2 = com.company.another.Class ... anObject = some.class.with.a.Map.property anObject.mapProperty = key1:$object1, key2:$object2
2) [users]
在用户比较少的情况下这种配置信息是有效的
[users] admin = secret lonestarr = vespa, goodguy, schwartz darkhelmet = ludicrousspeed, badguy, schwartz
3) [roles]
如果角色信息比较少的情况下可以使用这项配置
[roles] # 'admin' role has all permissions, indicated by the wildcard '*' admin = * # The 'schwartz' role can do anything (*) with any lightsaber: schwartz = lightsaber:* # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with # license plate 'eagle5' (instance specific id) goodguy = winnebago:drive:eagle5
4) [urls]
配置url等可访问的资源信息。