shiro作为一个功能强大而且可靠的安全框架拥有很多Api,结合spring可以很方便的实现有关shiro的使用。
这是关于shiro内部的架构图官网上的。下面做个简单的介绍:
subject:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
securityManager:安全管理器,主体进行认证和授权都 是通过securityManager进行。
authenticator:认证器,主体进行认证最终通过authenticator进行的。
authorizer:授权器,主体进行授权最终通过authorizer进行的。
sessionManager:web应用中一般是用web容器对session进行管理,shiro也提供一套session管理的方式。
SessionDao: 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao。
cache Manager:缓存管理器,主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和ehcache整合对缓存数据进行管理。
realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据。
下面时一些shiro提供的方法 可继承重写
Subject
Subject即主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。 Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权
SecurityManager
SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。
SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口。
Authenticator
Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。
Authorizer
Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。
realm
Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。
注意:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。
sessionManager
sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。
SessionDAO
SessionDAO即会话dao,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。
CacheManager
CacheManager即缓存管理,将用户权限数据存储在缓存,这样可以提高性能。
Cryptography
Cryptography即密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。
1.shiro的必要依赖
这里使用maven 所以我贴出pom的依赖包 ,如果需要手动导入的话可以下载相应的版本的jar包即可
<properties> <spring.version>4.2.4.RELEASE</spring.version> <shiro.version>1.4.0</shiro.version> </properties> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <!--这里spring的就不贴了根据需要导入吧 全部导入也ok没有冲突的-->
shiro在spring的applicationContext.xml的配置
<!-- shiroFilter 的webfilter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 管理器 必须配置 --> <property name="securityManager" ref="securityManager"></property> <!-- 拦截 跳转到的地址 通过地址去认证 --> <property name="loginUrl" value="/html/user_login.html"></property> <!-- 认证通过 可在登陆处理中跳转 也可配置如下 --> <property name="successUrl" value="/jsp/index.jsp"></property> <!-- 未认证跳转的连接 --> <property name="unauthorizedUrl" value="/error.html"></property> <property name="filterChainDefinitions"> <value> <!-- 静态资源设置匿名访问 --> /js/**=anon /css/**=anon /html/**=anon /jsp/**=anon /user/logOut=logout </value> </property> </bean> <!-- securityManager安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myRealm"></property> <!-- cacheManager 还可以在Realm中注册 反正注册到这里也是securityManager给realm调用 --> <property name="cacheManager" ref="cacheManager"></property> <!-- 注入 rememberMe cookie管理器 --> <property name="rememberMeManager" ref="rememberMeManager"></property> </bean> <!-- 自定义Realm 注册Realm --> <bean id="myRealm" class="com.dabai.realm.MyRealm"> <property name="cacheManager" ref="cacheManager"></property> <!-- 将凭证匹配器设置到realm中 realm按照凭证匹配器要求散列 --> <property name="credentialsMatcher" ref="credentialsMatcher"></property> <!--开启授权缓存 --> <property name="authorizationCachingEnabled" value="true" /> <!--缓存开启 --> <property name="cachingEnabled" value="true" /> <!--身份认证 --> <property name="authenticationCachingEnabled" value="true" /> <property name="authenticationCacheName" value="my" /> <!--权限认证 --> <property name="authorizationCacheName" value="my" /> </bean> <!-- 凭证匹配器 --> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <!-- md5散列 --> <property name="hashAlgorithmName" value="md5"></property> <!-- 一次 --> <property name="hashIterations" value="2"></property> <property name="storedCredentialsHexEncoded" value="true"></property> </bean> <!-- --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg name="name" value="jeesite.session.id" /> </bean> <!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- session失效时间 毫秒 --> <property name="globalSessionTimeout" value="60000"></property> <!-- 删除失效session --> <property name="deleteInvalidSessions" value="true"></property> </bean> <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:shiroEhcache.xml"></property> </bean> <!-- 缓存管理器 --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManager" ref="ehCacheManager"></property> </bean> <!-- rememberMeManager 管理器 写cookie 取出cookie生成用户信息 --> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <!-- 自定义cookie --> <property name="cookie" ref="rememberMeCookie"></property> </bean> <!-- 指定cookie --> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"></constructor-arg> <property name="httpOnly" value="true"></property> <property name="maxAge" value="604800"></property> </bean> <!-- --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- shiro end -->
上述有些东西是不需要的 如 ehcache的缓存 ,如果只是用于学习没有大量的数据的话可以不必配置,id="rememberMeCookie" 这个bean也可以不必使用 ,配置了如果开启的话,shiro会维护一个session用于校验登陆用户的身份,通过的话而且又在session的生命周期内时用户能够不登陆而以 shiro提供的 user 身份访问shirofilter 中设置拦截规则为 user的url
<bean id="cacheManager"这个也是不必要的 视需求吧 ,初步学习可以了解即可。其他的参考注释。2.shiro通过filter来进行拦截所以使用的话需要在web.xml中配置filter
<!-- spring 整合安全框架 由spring管理 配置原则上由spring配置 DelegatingFilterProxy作用时通知spring将所有的filter交给ShiroFilter --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 --> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <!-- 匹配所有保证所有的请求都经过shiro --> <url-pattern>/*</url-pattern> </filter-mapping>
记得 shiro的filter targetFilterLifecycle这个属性要配置上去。。。
这里说一下realm :
Realm:域,Realm 充当了 Shiro 与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息。从这个意义上讲,Realm 实质上是一个安全相关的 DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给 Shiro 。当配置 Shiro时,你必须至少指定一个 Realm ,用于认证和(或)授权。配置多个 Realm 是可以的,但是至少需要一个。
Shiro 内置了可以连接大量安全数据源(又名目录)的 Realm,如 LDAP、关系数据库(JDBC)、类似 INI 的文本配置资源以及属性文件等。如果缺省的 Realm 不能满足需求,你还可以插入代表自定义数据源的自己的 Realm 实现。
功能
Realm能做的工作主要有以下几个方面:
身份验证(getAuthenticationInfo 方法)验证账户和密码,并返回相关信息
权限获取(getAuthorizationInfo 方法) 获取指定身份的权限,并返回相关信息
令牌支持(supports方法)判断该令牌(Token)是否被支持
令牌有很多种类型,例如:HostAuthenticationToken(主机验证令牌),UsernamePasswordToken(账户密码验证令牌)
使用中可以自定义realm也可以用shiro提供的,通常我们会自定义realm
shiro在登陆逻辑处进行校验权限 realm中提供 一个父类 AuthorizingRealm,继承该类需要覆写两个方法 验证和授权 具体如下
package com.dabai.realm; import java.util.List; import javax.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import com.dabai.pojo.User; import com.dabai.service.UserService; /** * @author dabai: * * 类说明 shiro realm */ public class MyRealm extends AuthorizingRealm { @Resource(name = "userService") private UserService userService; @Override public void setName(String name) { super.setName(name); } @Override public String getName() { return "myRealm"; } // 授权 认证通过后才会执行 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); /* * 从principals获取主身份信息 将getPrimaryPrincipal方法返回值转为真实身份类型 */ if (principals == null || principals.getPrimaryPrincipal() == null) { return null; } User loginUser = (User) SecurityUtils.getSubject().getPrincipal(); // 获取权限 从数据库中取 根据用户角色查询其privilege List<String> privileges = userService.findPrivilegesById(loginUser); // realm中权限添加 for (String privilege : privileges) { info.addStringPermission(privilege); } return info; } // 认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 获取用户名 UsernamePasswordToken passwordToken = (UsernamePasswordToken) token; String username = passwordToken.getUsername(); if (username == null) { return null; } User checkUser = userService.checkRealmUserName(username); if (checkUser == null) { System.out.println("shiro 认证 当前登陆用户不存在"); throw new RuntimeException("shiro authentication failed"); } String password = checkUser.getPassword(); // 正确的验证信息 Token AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(checkUser, password,ByteSource.Util.bytes(username), this.getName()); return authcInfo; } }
realm中在登陆方法中被调用 参考如下的login方法
该方法在UserController中
public String login(User user, Model model ) { // 执行登陆逻辑 shiro的登陆逻辑 if (user == null || StringUtils.isBlank(user.getUsername())) return "user_login"; Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); try { subject.login(token); } catch (Exception e) { errorInfo = "wrong username or password"; model.addAttribute("errorInfo", errorInfo); return "user_login"; } User loginU = userService.checkRealmUserName(user.getUsername()); Session session = subject.getSession(true); session.setAttribute("loginUser", loginU); return "redirect:index"; }
subject.login(token);
上面那行会在shiro中调用realm的方法 还需要注意的是 授权方法只会在需要校验权限的时候被调用。
全部代码在
来源:https://www.cnblogs.com/notably/p/10676183.html