Introduction and configuration details of shiro security framework

Introduction:

Shiro is apache's a open source security framework , it will draw security authentication software systems related functions out to achieve user authentication, permissions, authorization , encryption, session management and other functions, to form a common security certification framework , using shiro can Complete the development of authentication, authorization and other functions very quickly, reducing system costs.

Summary structure:

Detailed structure:

The first layer: subject 

The second layer: securiryManager-   the core of Shiro, used to coordinate the work of management components

Authenticator: Authentication manager -  responsible for performing authentication operations

Authorizer: Authorization Manager -  responsible for authorization detection

Session manage :

The third layer: realm - Realm is the bridge between shiro and your application security data.

Actual combat:

配置Shiro安全过滤器

WEB-INF / web.xml

  <!-- 配置Shiro安全过滤器 -->
  <filter>
		<filter-name>DelegatingFilterProxy</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<!-- 初始化参数 -->
		<init-param>
			<param-name>targetBeanName</param-name>
			<param-value>shiroFilter</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>DelegatingFilterProxy</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

spring-configs.xml

    <!-- Configure shiro framework-->
    
    <!-- Configure realm object (will be managed by spring) -->
    <bean id="userRealm" 
            class="com.jt.sys.service.realm.ShiroUserRealm">
        < !-- Credential matcher (password encryption) -->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5 "/>
                <!-- <property name="hashIterations" value="1024"/> -->
            </bean>
        </property>
    </bean>
    <!-- Configure the CacheManager object (not necessary, mainly To improve performance,The authentication information and authorization information can be cached) -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <!-- Set a net.sf.ehcache.CacheManager instance here if you already have one.  If not, a new one
             will be creaed with a default config:
             <property name="cacheManager" ref="ehCacheManager"/> -->
        <!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance to inject, but you want
             a specific Ehcache configuration to be used, specify that here.  If you don't, a default
             will be used.: -->
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> 
    </bean>
    <!-- 配置securityManager对象(此对象时shiro框架核心) -->
    <bean id="securityManager" 
       class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"/> 
        <property name="cacheManager" ref="cacheManager"/>  
    </bean>
    <! - configuration ShiroFilter (achieved through this filter arrangement for filtering the resource request, which requests to release, which is to be authenticated) ->
    <the bean ID = "shiroFilter" class = "org.apache.shiro.spring.web.ShiroFilterFactoryBean ">
         <!-- The core security interface of shiro-->
         <property name="securityManager" ref="securityManager"/>
         <!-- Connection when logging in is required -->
         <property name="loginUrl" value=" /loginUI.do"></property>
         <!-- The connection to jump after a successful login (this has been processed in the login) -->
         <!-- <property name="successUrl" value="/index.jsp"></property>- ->
         <!-- When accessing unauthorized resources, the connection to jump 
         <property name="unauthorizedUrl" value="/default.html"></property>-->
         <!-- shiro connection constraint configuration- ->
         <property name="filterChainDefinitions">
             <value>
                 <!-- Allow anonymous access to static resource settings -->
                 /bower_components/** = anon
                 /build/** = anon
                 /dist/** = anon
                 /plugins /** = anon
                 /doLogin.do = anon
                 <!-- Exit-->
                 /doLogout.do = logout <!-- Subject's logout method will be called, this method will clear the session-->
                 <!                  --The remaining other paths must be authenticated before they can be accessed -->
/** = authc
             </value>
         </property>
     </bean>
     
    <!--Shiro生命周期处理器-->
    <bean id="lifecycleBeanPostProcessor" 
    class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    
    <!--启用shiro注解权限检查(@RequestPermissions)-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        depends-on="lifecycleBeanPostProcessor"/>
    <bean  class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" 
                  ref="securityManager"/>
    </bean>

 

Certification:

Certification process:

 

  1. The system calls the login method of subject to submit the user information token to the SecurityManager

          subject.login(token)

        // This request will be submitted to SecurityManager

        //SecurityManager will call the authentication processor Authenticator

        //The authentication processor will access the relevant Realm object to obtain authentication information

  1. SecurityManager delegates the authentication operation to the authenticator object Authenticator
  2. The Authenticator passes the identity information to Realm.

SysUser sysUser = sysUserDao.findUserByUserName(username);

  1. Realm accesses the database to obtain user information, then encapsulates the information and returns it.

        //3.2 Encapsulate user information

        AuthenticationInfo info

        = new SimpleAuthenticationInfo(

                sysUser.getUsername(), // Master identity

                sysUser.getPassword(), //The encrypted password

                byteSource, // The byte source object corresponding to salt

                getName()); //realm 's name

5) Authenticator authenticates the information returned by realm.

 

 

SysLoginController.java

@Controller
@RequestMapping("/")
public class SysLoginController {
	  @Autowired
      private SysUserService sysUserService;
	  @RequestMapping("loginUI")
	  public String loginUI(){
		  return "login";
	  }
	  @RequestMapping("doLogin")
	  @ResponseBody
	  public JsonResult doLogin(String username, String password){
		  String r=DigestUtils.md5DigestAsHex("123456".getBytes());
		  System.out.println("r="+r);
		    sysUserService.login(username, password);
		  return new JsonResult("login ok");
	  }
}

 

@Service
public class SysUserServiceImpl implements SysUserService {
	
	@Autowired
	private SysUserDao sysUserDao;
	@Autowired
	private SysRoleDao sysRoleDao;
	@Autowired
	private SysUserRoleDao sysUserRoleDao;
	
	@Override
	public void login(String username,String password) {
		System.out.println("service.login");
		//0.参数合法性验证
		if(StringUtils.isEmpty(username))
		throw new ServiceException("用户名不能为空");
		if(StringUtils.isEmpty(password))
		throw new ServiceException("密码不能为空");
		//1.获取Subject(主体)对象
		Subject subject=SecurityUtils.getSubject();
		//2.封装用户名和密码
		UsernamePasswordToken token=new UsernamePasswordToken(username, password);
	    //3.执行身份认证
		try {
		subject.login(token);
		//此请求会提交给SecurityManager
		//SecurityManager会调用认证处理器Authenticator
		//认证处理器会去访问相关Realm对象获取认证信息
		} catch (AuthenticationException e) {
		e.printStackTrace();
		throw new ServiceException("用户名或密码不正确");
		}
		//4.记录用户信息
		Session session=
		SecurityUtils.getSubject().getSession();
	    session.setAttribute("user", username);
	}

Inherit AuthorizingRealm and override doGetAuthenticationInfo

Realize basic authentication and permission control through Realm

public class ShiroUserRealm extends AuthorizingRealm {

	@Autowired
	private SysUserDao sysUserDao;

	/**
	 * 完成认证信息的获取以及封装
	 * 此方法何时调用?(执行登陆认证时调用)
	 * @param  
	 * 用于接收用户身份以及凭证信息的对象(用户输入的)
	 * 
	 * @return AuthenticationInfo  
	 * 封装了认证信息的对象(从数据库查询到的)
	 * 
	 * client-->controller-->service-->realm
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		System.out.println("realm.doGetAuthenticationInfo");
		//1.获取用户身份信息
		UsernamePasswordToken uToken= 	(UsernamePasswordToken)token;
		String username=uToken.getUsername();
		//2.基于用户身份查询数据库信息
		SysUser sysUser=
		sysUserDao.findUserByUserName(username);
		//3.对查询结果进行封装.
		//3.1获取用户salt值,并将其转换为一个字节源对象
		ByteSource byteSource= ByteSource.Util.bytes(sysUser.getSalt());
		//3.2对用户信息进行封装返回.
		AuthenticationInfo info=
		new SimpleAuthenticationInfo(
		sysUser.getUsername(), //主身份
		    sysUser.getPassword(), //已加密的密码
		    byteSource,//salt对应的字节源对象
		    getName());//realm 的名字
		return info;
	}
}

 

public interface SysUserDao {
	/**
	 * 根据用户名查找用户信息
	 * @param username
	 * @return
	 */
	SysUser findUserByUserName(String username);
}

 

     <select id="findUserByUserName" resultType="sysUser">
           select *  from sys_users
           where username=#{username}        
     </select>

Authorization implementation:

Process:

  1. The system calls the subject related method isPermitted to submit the user information to the SecurityManager based on the resource/hasRole

2) SecurityManager delegates permission detection operations to the Authorizer object

3) Authorizer delegates user information to realm. 

 List<String> list = sysUserDao.findUserPermissions(username);

  1. Realm accesses the database to obtain user authority information and encapsulate it .

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

info.setStringPermissions(permissions);

  1. Authorizer judges the user authorization information.

@RequiresPermissions("sys:user:update")

 

    @RequestMapping("doDeleteObject")
    @ResponseBody
    public JsonResult doDeleteObject(String idStr){
    	sysRoleService.deleteObject(idStr);
    	return new JsonResult();
    }

 

	@RequiresPermissions("sys:role:delete")
	@Override
	public int deleteObject(String idStr) {
		//1.参数合法性验证
		if(StringUtils.isEmpty(idStr))
		throw new ServiceException("必须选中才能删除");
		//2.解析字符串
		String[] ids=idStr.split(",");
		//3.调用数据层方法执行删除操作
		int rows=sysRoleDao.deleteObject(ids);
		
		for(String id:ids){
			sysRoleMenuDao.deleteObject(Integer.valueOf(id));
		    sysUserRoleDao.deleteObject(null, Integer.valueOf(id));
		}
		//4.返回处理结果
		if(rows==0)
		throw new ServiceException("数据已经不存在");
		return rows;
	}

Realize basic authentication and permission control through Realm

public class ShiroUserRealm extends AuthorizingRealm {
	
	@Autowired
	private SysUserDao sysUserDao;
	/***
	 * 完成授权信息的获取以及封装.
	 * 此方法何时调用?(执行授权检测时调用)
	 * 
	 */
	@Override
	protected AuthorizationInfo 
	doGetAuthorizationInfo(
			PrincipalCollection principals) {
		System.out.println("realm.doGetAuthorizationInfo");
		//1.获取登陆用户身份信息
		String username=
		(String)principals.getPrimaryPrincipal();
		//2.查找用户的权限信息
		List<String> list=//sys:user:update,sys:user:view,....,
		sysUserDao.findUserPermissions(username);
		System.out.println("list="+list);
		Set<String> permissions=new HashSet<>();
		for(String permission:list){
			if(!StringUtils.isEmpty(permission)){
				permissions.add(permission);
			}
		}
		
		System.out.println("set="+permissions);
		//3.对权限信息进行封装
		SimpleAuthorizationInfo info=
		new SimpleAuthorizationInfo();
		info.setStringPermissions(permissions);
		return info;
	}

 

	/**
	 * 根据用户id查找用户权限标识信息
	 * 例如:sys:role:view,sys:role:add
	 * @param userId
	 * @return
	 */
	List<String> findUserPermissions(String username);

 

     <select id="findUserPermissions"
             resultType="string">
           select m.permission
           from sys_users u join 
                sys_user_roles ur join 
                sys_role_menus rm join 
                sys_menus m
                
                on u.id=ur.user_id   and 
                ur.role_id=rm.role_id  and 
                rm.menu_id=m.id 
           where u.username=#{username}
     </select>
 <!-- 整合Shiro 安全框架-->
 
  <dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.3.2</version>
  </dependency>

 

Related table:

sys_roles

sys_users

sys_menus

sys_role_menus

sys_user_roles

CREATE TABLE `sys_roles` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL COMMENT '角色名称',
  `note` varchar(500) DEFAULT NULL COMMENT '备注',
  `createdTime` datetime DEFAULT NULL COMMENT '创建时间',
  `modifiedTime` datetime DEFAULT NULL COMMENT '修改时间',
  `createdUser` varchar(20) DEFAULT NULL COMMENT '创建用户',
  `modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用户',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8 COMMENT='角色';
CREATE TABLE `sys_users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) DEFAULT NULL COMMENT '密码',
  `salt` varchar(50) DEFAULT NULL COMMENT '盐  密码加密时前缀,使加密后的值不同',
  `email` varchar(100) DEFAULT NULL COMMENT '邮箱',
  `mobile` varchar(100) DEFAULT NULL COMMENT '手机号',
  `valid` tinyint(4) DEFAULT NULL COMMENT '状态  0:禁用   1:正常  默认值 :1',
  `createdTime` datetime DEFAULT NULL COMMENT '创建时间',
  `modifiedTime` datetime DEFAULT NULL COMMENT '修改时间',
  `createdUser` varchar(20) DEFAULT NULL COMMENT '创建用户',
  `modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用户',
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='系统用户';
CREATE TABLE `sys_menus` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL COMMENT '资源名称',
  `url` varchar(200) DEFAULT NULL COMMENT '资源URL',
  `type` int(11) DEFAULT NULL COMMENT '类型     1:菜单   2:按钮',
  `sort` int(11) DEFAULT NULL COMMENT '排序',
  `note` varchar(100) DEFAULT NULL COMMENT '备注',
  `parentId` int(11) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
  `permission` varchar(500) DEFAULT NULL COMMENT '授权(如:user:create)',
  `createdTime` datetime DEFAULT NULL COMMENT '创建时间',
  `modifiedTime` datetime DEFAULT NULL COMMENT '修改时间',
  `createdUser` varchar(20) DEFAULT NULL COMMENT '创建用户',
  `modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用户',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=141 DEFAULT CHARSET=utf8 COMMENT='资源管理';
CREATE TABLE `sys_role_menus` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_id` int(11) DEFAULT NULL COMMENT '角色ID',
  `menu_id` int(11) DEFAULT NULL COMMENT 'ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1218 DEFAULT CHARSET=utf8 COMMENT='角色与菜单对应关系';
CREATE TABLE `sys_user_roles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL COMMENT '用户ID',
  `role_id` int(11) DEFAULT NULL COMMENT '角色ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8 COMMENT='用户与角色对应关系';
INSERT INTO `jt_sys`.`sys_users`(`id`, `username`, `password`, `salt`, `email`, `mobile`, `valid`, `createdTime`, `modifiedTime`, `createdUser`, `modifiedUser`) VALUES (1, 'admin', '4ebd394fbd25e495e0753a7dc9889a8e', '7adb778c-e7d3-4dd3-a3c5-5f80a158006d', '[email protected]', '13624356789', 1, NULL, '2018-01-13 02:06:45', NULL, 'admin');
 
INSERT INTO `jt_sys`.`sys_menus`(`id`, `name`, `url`, `type`, `sort`, `note`, `parentId`, `permission`, `createdTime`, `modifiedTime`, `createdUser`, `modifiedUser`) VALUES (45, '用户管理', 'user/listUI.do', 1, 45, NULL, 8, 'sys:user:view', '2017-07-12 15:15:59', '2017-07-21 17:36:01', 'admin', 'admin');
 

 

Guess you like

Origin blog.csdn.net/qq_24271537/article/details/109324820