Shiro(二)——拦截器、角色和权限
Shiro(一)的代码十分简单,仅仅展示效果,在Shiro(一)的基础上,进行改进
Xml配置
配置主要看ShiroFilterFactoryBean配置,其它配置的按照需求添加,还有注解、缓存的相关配置等等
filterChainDefinitions:用于配置访问一个页面,需要经过的Filter拦截器、需要的角色和权限,语法如下:
- anon:例子/admins/**=anon表示可以匿名访问
- authc:例如/admins/user/**=authc表示需要认证才能使用,没有参数
- perms:例子/page_base_staff.action = perms["staff"],当前用户需要有staff权限才可以访问。
- roles:例子/admins/user/**=roles[admin],当前用户是否有这个角色权限。
- 拦截器直接写拦截器的名称即可,如以下配置中的login拦截器
filters:可配置多个拦截器,后面介绍拦截器用法
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd"> <bean id="login" class="com.sea.shiro.LoginFilter" /> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="successUrl" value="/member/index.htm" /> <property name="loginUrl" value="/login.htm" /> <property name="unauthorizedUrl" value="/error.htm" /> <property name="filterChainDefinitions"> <value> /login.htm=anon /submit.htm=anon /error.htm=anon /member/**=login,authc,roles["member"],perms["query"] </value> </property> <property name="filters"> <util:map> <entry key="login" value-ref="login"></entry> </util:map> </property> </bean> <!-- 授权 认证 --> <bean id="shiroRealm" class="com.sea.shiro.ShiroRealm" /> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroRealm" /> </bean> <!-- Shiro生命周期处理器 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> </beans>
AuthorizingRealm授权领域
这个类就是Xml配置中的shiroRealm对象,主要做两件事,角色授权,账号认证,需要改写的函数如下:
doGetAuthorizationInfo:角色授权,主要就是配置用户的角色和权限两个信息,这决定了你能在此系统中做什么事;
doGetAuthenticationInfo:角色认证,简而言之,就是让服务器记住你已经登录过了。
package com.sea.shiro; import java.util.HashSet; import java.util.Set; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AccountException; 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 com.sea.spring.entity.User; /** * 授权领域 * @author ChenSS on 2018年4月18日 */ public class ShiroRealm extends AuthorizingRealm { /** * 授权:角色分配 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { User user = (User) SecurityUtils.getSubject().getPrincipal(); System.out.println(user); //TODO: 根据User查找权限和角色 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); Set<String> roles = new HashSet<>(); roles.add("member"); info.setRoles(roles); Set<String> permissions = new HashSet<>(); permissions.add("query"); info.setStringPermissions(permissions); return info; } /** * 认证信息,主要针对用户登录, */ @SuppressWarnings("unused") @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; System.out.println("AuthenticationInfo" + token.getUsername()); System.out.println(token.getPassword()); System.out.println("AuthenticationInfo" + token.getHost()); System.out.println("AuthenticationInfo" + token.getPrincipal()); //TODO:根据账号和密码查询用户 User user = new User("shiro", "123456"); if(null == user){ throw new AccountException("帐号或密码不正确!"); } else if(true) { } else { //TODO: 记录最后登录时间 } return new SimpleAuthenticationInfo(user, user.getPassword(), getName()); } }
登录拦截器
可继承Shiro包下的AccessControlFilter类,该类的主要方法如下:
- isAccessAllowed:表示是否允许访问;如果允许访问返回true,否则false;
- onAccessDenied:表示当访问拒绝时是否已经处理;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。
package com.sea.shiro; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.shiro.SecurityUtils; import org.apache.shiro.web.filter.AccessControlFilter; import com.sea.spring.entity.User; /** * * @author ChenSS on 2018年4月18日 */ public class LoginFilter extends AccessControlFilter { final static Class<LoginFilter> CLASS = LoginFilter.class; @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { System.out.println("LoginFilter "); User token = (User) SecurityUtils.getSubject().getPrincipal(); System.out.println(token); if (null != token || isLoginRequest(request, response)) { return Boolean.TRUE; } if (ShiroUtils.isAjax(request)) { Map<String, String> resultMap = new HashMap<String, String>(); resultMap.put("login_status", "300"); resultMap.put("message", "当前用户没有登录"); //因为是Ajax请求,以Json格式写回客户端,具体实现以自己代码习惯为准 ShiroUtils.out(response, resultMap); } return Boolean.FALSE; } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { // 保存Request和Response 到登录后的链接 saveRequestAndRedirectToLogin(request, response); return Boolean.FALSE; } }
登录Controller
函数同Shiro(一),主要就是在SecurityUtils.getSubject()中添加你的用户
package com.sea.spring.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.sea.spring.entity.User; @Controller public class LoginController { @RequestMapping(value = "/login") public ModelAndView login() { return new ModelAndView("/login"); } @RequestMapping(value = "/submit") public ModelAndView submit(String username, String password) { User user = new User("shiro", "123456"); try { // 如果登陆成功 if (user.getName().equals(username) && user.getPassword().equals(password)) { UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword().toString()); Subject subject = SecurityUtils.getSubject(); subject.login(token); } } catch (Exception e) { e.printStackTrace(); } return new ModelAndView("redirect:/member/index.htm"); } }
疯狂的妞妞 :每一天,做什么都好,不要什么都不做!