shiro初识

1、什么是Shiro 官网:http://shiro.apache.org/html

Apache Shiro是一个强大易用的Java安全框架,提供了认证、受权、加密和会话管理等功能;

认证 - 用户身份识别,常被称为用户“登陆”;

受权 - 访问控制;

密码加密 - 保护或隐藏数据防止被偷窥;

会话管理 - 每用户相关的时间敏感的状态。

对于任何一个应用程序,Shiro均可以提供全面的安全管理服务。而且相对于其余安全框架,Shiro要简单的多。

2、Shiro的架构介绍 首先,来了解一下Shiro的三个核心组件:Subject, SecurityManager 和 Realms. 以下图: 输入图片说明java

Subject:即“当前操做用户”。可是,在Shiro中,Subject这一律念并不只仅指人,也能够是第三方进程、后台账户(Daemon Account)或其余相似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你能够把它认为是Shiro的“用户”概念。 Subject表明了当前用户的安全操做,SecurityManager则管理全部用户的安全操做。web

SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro经过SecurityManager来管理内部组件实例,并经过它来提供安全管理的各类服务。算法

Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“链接器”。也就是说,当对用户执行认证(登陆)和受权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。 从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的链接细节,并在须要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)受权。配置多个Realm是能够的,可是至少须要一个。spring

Shiro内置了能够链接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、相似INI的文本配置资源以及属性文件等。若是缺省的Realm不能知足需求,你还能够插入表明自定义数据源的本身的Realm实现。数据库

输入图片说明

除前文所讲Subject、SecurityManager 、Realm三个核心组件外,Shiro主要组件还包括:apache

Authenticator :认证就是核实用户身份的过程。这个过程的常见例子是你们都熟悉的“用户/密码”组合。多数用户在登陆软件系统时,一般提供本身的用户名(当事人)和支持他们的密码(证书)。若是存储在系统中的密码(或密码表示)与用户提供的匹配,他们就被认为经过认证。编程

Authorizer :受权实质上就是访问控制 - 控制用户可以访问应用中的哪些内容,好比资源、Web页面等等。缓存

SessionManager :在安全框架领域,Apache Shiro提供了一些独特的东西:可在任何应用或架构层一致地使用Session API。即,Shiro为任何应用提供了一个会话编程范式 - 从小型后台独立应用到大型集群Web应用。这意味着,那些但愿使用会话的应用开发者,没必要被迫使用Servlet或EJB容器了。或者,若是正在使用这些容器,开发者如今也能够选择使用在任何层统一一致的会话API,取代Servlet或EJB机制。安全

CacheManager :对Shiro的其余组件提供缓存支持。

3、代码整合: 1)、pom中加入shiro所需jar ``` <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</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-aspectj</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-cas</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-spring</artifactId> <version>${shiro.version}</version> </dependency>

```

2)、web.xml配置shiro拦截器及加载shiro配置文件:

<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:spring-context*.xml
			classpath:shiro-context.xml
		</param-value>
	</context-param>

        <!-- 确保Web项目中须要权限管理的URL均可以被Shiro拦截过滤 -->
	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

3)、编写shiro配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"
	default-lazy-init="true">
	
	<!-- shiro -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean> 
	<!-- 数据库保存的密码是使用MD5算法加密的,因此这里须要配置一个密码匹配对象 -->  
    <!-- <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.Md5CredentialsMatcher"></bean>  -->
    <!-- 缓存管理 -->  
    <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"></bean> 
	<!--   
	      使用Shiro自带的JdbcRealm类  
	      指定密码匹配所须要用到的加密对象  
	      指定存储用户、角色、权限许可的数据源及相关查询语句  
     -->
	<!-- <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">  
        <property name="credentialsMatcher" ref="credentialsMatcher"></property>  
        <property name="permissionsLookupEnabled" value="true"></property>  
        <property name="dataSource" ref="dataSource"></property>  
        <property name="authenticationQuery"  
            value="SELECT pswd FROM u_user WHERE mobileId = ?"></property>  
        <property name="userRolesQuery"  
            value="select u_role.name from u_role,u_user_role,u_user where u_role.id = u_user_role.rid and u_user_role.uid = u_user.id and u_user.mobileId = ?"></property>  
        <property name="permissionsQuery"  
            value="select u_permission.* from u_permission,u_role_permission,u_role where u_permission.id=u_role_permission.pid and u_role_permission.rid = u_role.id and u_role.`name` = ?"></property>  
    </bean> -->
    
    <!-- Realm实现 -->
    <bean id="userRealm" class="com.company.project.common.shiro.UserRealm"></bean>
    
    
    <!-- Shiro安全管理器 -->  
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
        <property name="realm" ref="userRealm"></property>  
        <property name="cacheManager" ref="cacheManager"></property>  
    </bean>
    <!--   
       Shiro主过滤器自己功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行  
       Web应用中,Shiro可控制的Web请求必须通过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持   
    -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全接口,这个属性是必须的 -->  
        <property name="securityManager" ref="securityManager"></property>  
        <!-- 要求登陆时的连接(登陆页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->  
        <property name="loginUrl" value="/company/login"></property>  
        <!-- 登陆成功后要跳转的链接(本例中此属性用不到,由于登陆成功后的处理逻辑在LoginController里硬编码) -->  
        <!-- <property name="successUrl" value="/" ></property> -->  
        <!-- 用户访问未对其受权的资源时,所显示的链接 -->  
        <property name="unauthorizedUrl" value="/"></property>  
        <property name="filterChainDefinitions">  
            <value>  
            	/company/login=anon
                /company/subLogin=anon
                /company/**=authc
            </value>  
        </property>  
    </bean>
	<!--   
       开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,  
       并在必要时进行安全逻辑验证  
    -->  
    <!--  
    <bean  
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>  
    <bean  
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">  
        <property name="securityManager" ref="securityManager"></property>  
    </bean>  
    -->
</beans>

4)、编写自定义Realm实现类,该类继承自AuthorizingRealm,实现其接口

package com.company.project.common.shiro;

import java.util.Date;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
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.springframework.beans.factory.annotation.Autowired;

import com.company.project.common.shiro.token.ShiroToken;
import com.company.project.common.utils.Constants;
import com.company.project.common.utils.DateUtils;
import com.company.project.modules.user.entity.User;
import com.company.project.modules.user.service.PermissionService;
import com.company.project.modules.user.service.RoleService;
import com.company.project.modules.user.service.UserService;

/**
 * 自定义shiro的Realm
 * @author Sorin
 *
 */
public class UserRealm extends AuthorizingRealm{

	@Autowired
	private UserService userService;
	
	@Autowired
	private PermissionService permissionService;
	
	@Autowired
	private RoleService roleService;
	
	/**
	 * 该类的做用是为shiro提供认证数据源
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		ShiroToken token = (ShiroToken) authcToken;
		User user = userService.subLogin(token.getUsername(), token.getPswd());
		if(user == null){
			throw new UnknownAccountException("账号或密码不正确!");// 没找到账号
		}else if(Constants.MobileCode.ISTRUE== user.getStatus()){
			throw new DisabledAccountException("账号已经禁止登陆!");
		}else{//更新最后登陆时间
			user.setLastLoginTime(DateUtils.getFormattedString(new Date()));
			userService.update(user);
		}
		return new SimpleAuthenticationInfo(user.getMobileId(), // 用户名
				user.getPswd(), // 密码
				getName() // realm name
		);
	}
	
	/**
	 * 拼装shiro的受权数据源
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String mobileId = (String)principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		//角色
		Set<String> findRoles = roleService.findRoles(mobileId);
		String roleName = null;
		for (String role : findRoles) {
			roleName = role;
		}
		authorizationInfo.setRoles(findRoles);
		//权限
		authorizationInfo.setStringPermissions(permissionService.findPermission(roleName));
		return authorizationInfo;
	}

	

}

6)、自定义ShiroToken实体类,继承UsernamePasswordToken

package com.company.project.common.shiro.token;

import org.apache.shiro.authc.UsernamePasswordToken;

public class ShiroToken extends UsernamePasswordToken  implements java.io.Serializable{

	private static final long serialVersionUID = -6451794657814516274L;

	public ShiroToken(String username, String pswd) {
		super(username,pswd);
		this.pswd = pswd ;
	}
	
	
	/** 登陆密码[字符串类型] 由于父类是char[] ] **/
	private String pswd ;

	public String getPswd() {
		return pswd;
	}


	public void setPswd(String pswd) {
		this.pswd = pswd;
	}
}

7)、TokenManager类,调用shiro认证的service

public static String login(LoginVo user){
		ShiroToken token = new ShiroToken(user.getMobileId(), user.getPswd());
		token.setRememberMe(user.getIsRememberMe());
		SecurityUtils.getSubject().login(token);
		return getToken();
	}

    public static String getToken(){
		return (String)SecurityUtils.getSubject().getPrincipal();
	}

8)、LoginController类

//捕捉相应的异常进行处理便可
try{
    String mobileId = TokenManager.login(loginVo);
}catch (DisabledAccountException e) {
	e.printStackTrace();
	return resultBase("账号已经禁用。", Constants.ResponseResultFlag.ERROR);
} catch (Exception e) {
    e.printStackTrace();
    return resultBase("账号或密码错误。", Constants.ResponseResultFlag.ERROR);
}

9)、shiro标签使用:

<%--shiro 标签 --%>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %> 
....

<%--拥有 角色(管理员) || (用户中心)--%>
<shiro:hasAnyRoles name='系统管理员,用户中心'>
<shiro:hasPermission name="/member/list.shtml">
<li><a href="/member/list.shtml">用户列表</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="/member/online.shtml">
<li><a href="/member/online.shtml">在线用户</a></li>
</shiro:hasPermission>
相关文章
相关标签/搜索