ps:
一.环境:SpringMvc+spring+Mybatis,前后端分离,只支持单台项目(未实现单点登入);
二.需对shiro原理流程,有基础的理解,以及用户权限需求的应用场景明了,能更好项目整合;
三.shiro的基本构成:
1.Subject (接口) : 主体(当前用户) 定义了认证授权的相关函数,通过SecurityManage 安全管理器进行授权按认证
2.SecurityManage (接口) : 框架核心核心 安全管理器,对subject进行认证,授权
3.Authenticator : 认证器,对主体进行认证(登入)
4.Authorizer : 授权器,通过认证后,在访问功能接口时,通过授权器判断用户是否有该功能的操作权限
5.Realm : 读取用户权限数据, 进行安全认证需要通过realm,获取用户权限数据
6.SessionManage : 会话管理器,自定义了一套,不依赖http的session
7.SessionDAO : 操作会话信息,例如将会话信息存储到redis库
8.CacheManage : 缓存管理器 ,将用户权限数据存储在缓存
9.Cryptography : 加密
demo
1.maven依赖:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>org.ehcache</groupId> <artifactId>ehcache</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency>
2.spring整合shiro配置:
1)spring.xml <!--自定义的relam--> <bean name="shiroRealm" class="hotkidclub.shiro.ShiroRealm"/> <!--缓存管理器--> <bean name="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/> <!--shiro安全管理器--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroRealm"/> <property name="cacheManager" ref="shiroCacheManager"/> </bean> <!-- 启动安全管理器: 相当于调用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <!-- shiro 的Web过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!--如果没有认证将要跳转的登陆地址 --> <property name="loginUrl" value="/login"/> <!-- 配置安全规则:1). anon 可以被匿名访问 2). authc 必须认证(即登录)后才可能访问的页面 --> <property name="filterChainDefinitions"> <value> <!-- 登录不拦截 --> / = anon /static/** = anon /login.ctrl = anon /** = authc </value> </property> </bean> <!-- AOP式方法级权限检查 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <!-- Shiro生命周期处理器--> <bean name="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
2)web.xml
<!-- shiro过虑器 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>*.ctrl</url-pattern> </filter-mapping>
<!-- 接收接口请求适配器 --> <servlet> <servlet-name>backend_shiro_demo</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>backend_shiro_demo</servlet-name> <url-pattern>*.ctrl</url-pattern> </servlet-mapping>
3).自定义shiro的realm
package hotkidclub.shiro; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.Session; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; public class ShiroRealm extends AuthorizingRealm { /** * 认证器 : * <p> * 本平台用户登入接口调用-subject.login() : 回调该函数 * </p> * * @param authcToken 凭证信息:可存放用户账号密码 * @return 认证信息:包含当前请求登入的用户信息 * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { System.out.println("认证开始"); Subject subject = SecurityUtils.getSubject(); // 1.获取认证的主体信息:账户密码...,TODO authcToken转换为本平台业务bean UsernamePasswordToken token = (UsernamePasswordToken) authcToken; // 2.对比数据库存储的账号密码 // 3.创建简单认证信息对象 : new SimpleAuthenticationInfo(object, object, 字符串);可传递自定义对象,字符内容; Session session = subject.getSession(); session.setAttribute("user", token.getPrincipal()); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName()); return info; } /** * 授权器 : 校验用户的角色和权限 * <p> * 本平台接口配置角色/权限的授权注解时 : 回调该函数 * </p> * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // TODO 1.通过用户名去数据库查询该用户有哪些角色和权限 // TODO 2.设置角色信息 // TODO 3.设置权限信息 // 创建简单授权信息对象 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addRole("admin"); info.addStringPermission("add"); System.out.println("鉴权完成"); return info; } }
3.测试
//登入
@ResponseBody
@PostMapping(value = "/login.ctrl", produces = "application/json")
public Map<String, Object> login(@RequestBody Map<String, Object> params, HttpSession httpSession) {
Object object = null;
// shiro login
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(账号,密码 );
subject.login(token);
object = result;
return object;
}
/**
* 测试:角色/权限的核查
*
* @param session
* @return
*/
@ResponseBody
@RequiresRoles(value = "admin")//鉴查角色注解
@RequiresPermissions(value = "add")//鉴权注解
@GetMapping(value = "/check.ctrl", produces = "application/json") // @RequiresPermissions (value={"add", "update"}, logical= Logical.OR)
public Map<String, Object> permission(HttpSession session) {
String object = null;try {
Subject subject = SecurityUtils.getSubject();
object = "ok";
}
return object;
}