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