Shiro权限管理与整合

shiro原理流程图

shiro授权方式

  • 编程式:通过写if/else 授权代码块完成【ini配置文件】

    Subject subject = SecurityUtils.getSubject();
    if(subject.hasRole(“admin”)) {
        //有权限
    } else {
        //无权限
    }
复制代码
  • 注解式:通过在执行的Java方法上放置相应的注解完成

    @RequiresRoles("admin")
    public void hello() {
    //有权限
    }
复制代码
  • JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成

<shiro:hasRole name="admin">
    <!— 有权限—>
</shiro:hasRole>
复制代码
  • 自定义realm大致流程

shiro配置与详解

  • pom 导入


               <dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-web</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-ehcache</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-quartz</artifactId>
			<version>1.2.3</version>
		</dependency>

复制代码
  • web.xml

    <!-- 配置Shiro过滤器 -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由servlet container管理 -->
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
复制代码
  • applicationContext-shiro.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">

	<!-- realm实现,继承自AuthorizingRealm -->
	<bean id="userRealm" class="org.j.shiro.security.UserRealm"/>
	<bean id="emailRealm" class="org.j.shiro.security.EmailRealm"/>

	<!-- 会话管理器 -->
	<bean id="sessionManager" class="org.j.shiro.session.UserSessionManager">
		<property name="globalSessionTimeout" value="1800000"></property>
		<property name="sessionDAO" ref="sessionDAO"/>
		<property name="sessionValidationSchedulerEnabled" value="true"></property>
		<property name="sessionIdUrlRewritingEnabled" value="false"></property>
		<property name="sessionListeners">
			<list><ref bean="sessionListener"/></list>
		</property>
		<property name="sessionFactory" ref="sessionFactory"/>
	</bean>

	<!-- 安全管理器 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="sessionManager" ref="sessionManager"></property>
		<!-- <property name="realm" ref="userRealm"/> -->
	     <!-- 配置多个Realm -->
        <property name="authenticator" ref="authenticator"></property>
	</bean>
	
	<!-- 配置多个Realm -->
	<!-- org.apache.shiro.authc.pam.ModularRealmAuthenticator -->
       <bean id="authenticator" class="org.j.shiro.security.MyModularRealmAuthenticator">
        <property name="realms">
            <list>
                <ref bean="userRealm"/>
                <ref bean="emailRealm"/>
            </list>
        </property>
       </bean>

	<!-- Shiro过滤器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
	    <property name="securityManager" ref="securityManager"/>
	    <property name="loginUrl" value="/authadmin/login.html"/>
	    <property name="successUrl" value="/authadmin/index.html"/>
	    <property name="unauthorizedUrl" value="/WEB-INF/view/error/403.html"/>
	    <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" />
	</bean>
	
	<!--自定义filterChainDefinitionMap -->
	<bean id="chainDefinitionSectionMetaSource" class="org.j.shiro.security.ChainDefinitionSectionMetaSource">
		<property name="filterChainDefinitions">
			<value>
			/favicon.ico=anon
			/statics/**=anon
                        /WEB-INF/view/error/**=anon
	        	/login.html=anon
	        	/upload/**=anon
	        	
	        	/sys/login=anon
	        	/sys/**=authc
	        	/authadmin/login.html=anon
			</value>
		</property>
	</bean>

	<!-- 会话DAO -->
	<bean id="sessionDAO" class="org.j.shiro.session.UserSessionDAO"/>

	<!-- 会话监听器 -->
	<bean id="sessionListener" class="org.j.shiro.listener.UserSessionListener"/>

	<!-- session工程 -->
	<bean id="sessionFactory" class="org.j.shiro.session.UserSessionFactory"/>
	
        <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

	<!-- 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>
	
</beans>
复制代码

分析执行流程

        @ResponseBody
	@RequestMapping(value = "/sys/login", method = RequestMethod.POST)
	public R login(String username, String password, String captcha)throws IOException {
		String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
		if(!captcha.equalsIgnoreCase(kaptcha) && false){
			return R.error("验证码不正确");
		}
		
		try{
			Subject subject = ShiroUtils.getSubject();
			password = MD5Utils.encrypt(username, password);//sha256加密
			UsernamePasswordToken token = new UsernamePasswordToken(username, password);
			subject.login(token);//提交认证
		}catch (UnknownAccountException e) {
			return R.error(e.getMessage());
		}catch (IncorrectCredentialsException e) {
			return R.error(e.getMessage());
		}catch (LockedAccountException e) {
			return R.error(e.getMessage());
		}catch (AuthenticationException e) {
			return R.error("账户验证失败");
		}
	    
		return R.ok();
	}
复制代码
public class ShiroRealm extends AuthorizingRealm{
	
	@Autowired
	private UserMapper userMapper;
	
	@Autowired
	private UserService userService;

	/**
	 * 授权【验证权限时调用】
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		Object principal = principals.getPrimaryPrincipal();
		Long userId = ShiroUtils.getUserId();
		//查询用户角色
		Set<String> rolesSet = userService.listUserRoles(userId);
		//查询用户权限
		Set<String> permsSet = userService.listUserPerms(userId);
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.setRoles(rolesSet);
		info.setStringPermissions(permsSet);
		return info;
	}

	/**
	 * 认证【登陆时调用】
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		String username = (String)token.getPrincipal();
		String password = new String((char[]) token.getCredentials());
		//根据用户名查询用户信息
		User user = userMapper.findUserByUsername(username);
		//账户不存在
		if(user == null) {
            throw new UnknownAccountException("账号或密码不正确");
        }
		//需要判断密码是否错误	
		if(!password.equals(user.getUserPwd())) {//可加逻辑判断
			throw new IncorrectCredentialsException("账号或密码不正确");
		}
		//需要判断账号是否启用
		if(user.getUserStatus() == 0) {
			throw new LockedAccountException("账号已被锁定,请联系管理员");
		}
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
		return info;
	}
}
复制代码
  • shiro自定义工具类

public class ShiroUtils {

	public static Session getSession() {
		return SecurityUtils.getSubject().getSession();
	}

	public static Subject getSubject() {
		return SecurityUtils.getSubject();
	}
	
	public static SysUserEntity getUserEntity() {
	    SysUserEntity user = (SysUserEntity)SecurityUtils.getSubject().getPrincipal();
        return user==null?(SysUserEntity)getSessionAttribute("user"):user;
	}

	public static Long getUserId() {
		return getUserEntity().getUserId();
	}
	
	public static void setSessionAttribute(Object key, Object value) {
		getSession().setAttribute(key, value);
	}

	public static Object getSessionAttribute(Object key) {
		return getSession().getAttribute(key);
	}

	public static boolean isLogin() {
		return SecurityUtils.getSubject().getPrincipal() != null;
	}

	public static void logout() {
		SecurityUtils.getSubject().logout();
	}
	
	public static String getKaptcha(String key) {
		String kaptcha = getSessionAttribute(key).toString();
		getSession().removeAttribute(key);
		return kaptcha;
	}

}
复制代码
  • MD5工具类

public class MD5Utils {

	private static final String SALT = "asd6af1lks";
	
	private static final String ALGORITH_NAME = "md5";
	
	private static final int HASH_ITERATIONS = 2;

	/**
	 * 使用md5生成加密后的密码
	 * @param user
	 * @return
	 */
	public static String encrypt(String pswd) {
		String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex();
		return newPassword;
	}
	
	/**
	 * 使用md5生成加密后的密码
	 * @param user
	 * @return
	 */
	public static String encrypt(String username, String pswd) {
		String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT), HASH_ITERATIONS).toHex();
		return newPassword;
	}
	
}
复制代码

未完待续

猜你喜欢

转载自juejin.im/post/5d6880d251882566ce35a49b