shiro权限认证框架学习

shiro与spring Secuity比较:

1 简单灵活

2 科托离spring

3 粒度较粗

spring Secuity与之相反,同时它也是又shiro开发

shiro认证过程:

1  创建secrityManger

2 主体提交认证

3 securityManger认证

4 Realm验证

5 Authenticor认证

代码:

package com.imooc.test;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;

/**认证
 * @author fusiping
 * 2018年11月23日
 */
public class AuthenticationTest {

	SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
	
	@Before
	public void addUser() {
		simpleAccountRealm.addAccount("Mark","123456");
	}
	
	@Test
	public  void testAuthentication() {
		//1.构建securityManage环境
		DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
		defaultSecurityManager.setRealm(simpleAccountRealm);
		
		//设置secutityManager环境
		SecurityUtils.setSecurityManager(defaultSecurityManager);
		//2.主体提交认证请求
		Subject subject = SecurityUtils.getSubject();
		
		UsernamePasswordToken token =  new UsernamePasswordToken("Mark","123456");
		
		subject.login(token);
		//结果:isAuthenticated:true
		System.out.println("isAuthenticated:"+subject.isAuthenticated());
		
		subject.logout();
		//结果:isAuthenticated:false
		System.out.println("isAuthenticated:"+subject.isAuthenticated());
		
	}
}

shiro授权:

1 创建SecurityManage

2 主体授权

3 securitymanager授权

4 authorizer授权

5 Realm获取角色权限数据

代码:

package com.imooc.test;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;

/**认证
 * @author fusiping
 * 2018年11月23日
 */
public class AuthenticationTest {

	SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
	
	@Before
	public void addUser() {
		simpleAccountRealm.addAccount("Mark","123456","admin");
	}
	
	/**
	 * 授权
	 */
	@Test
	public  void testAuthorizer() {
		//1.构建securityManage环境
		DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
		defaultSecurityManager.setRealm(simpleAccountRealm);
		
		//设置secutityManager环境
		SecurityUtils.setSecurityManager(defaultSecurityManager);
		//2.主体提交认证请求
		Subject subject = SecurityUtils.getSubject();
		
		UsernamePasswordToken token =  new UsernamePasswordToken("Mark","123456");
		subject.login(token);
		
		//结果:isAuthenticated:true
		System.out.println("isAuthenticated:"+subject.isAuthenticated());
		
		//没有抛出异常,说明验证成功
		subject.checkRole("admin");
		
	}
	
	
}

shiro自定义Realm

内置Realm:IniRealm,JdbcRealm

package com.imooc.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

public class IniRealmTest {

    @Test
    public  void testIniRealmr() {
        //自定义
        IniRealm iniRealm =  new IniRealm("classpath:user.ini");
        //1.构建securityManage环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(iniRealm);
        //设置secutityManager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //2.主体提交认证请求
        Subject subject = SecurityUtils.getSubject();
        
        UsernamePasswordToken token =  new UsernamePasswordToken("Mark","123456");
        subject.login(token);
        
        //结果:isAuthenticated:true
        System.out.println("isAuthenticated:"+subject.isAuthenticated());
        
        subject.checkRole("user1");
        subject.checkPermission("user:update");
    }
}

user.ini文件:

[users]
Mark=123456,admin,user1
[roles]
admin=user:delete
user1=user:update

jdbcRealm实例:

package com.imooc.test;

import javax.swing.JScrollBar;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

import com.alibaba.druid.pool.DruidDataSource;

public class JdbcRealmTest {
    
    DruidDataSource dataSource = new DruidDataSource();
    {
        dataSource.setUrl("jdbc:mysql://localhost:3333/test1");
        dataSource.setUsername("test1");
        dataSource.setPassword("fsp648734!");
    }

    @Test
    public  void testIniRealmr() {
        
        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(dataSource);
        //使用jdbcRealm必须设置开关为true,默认为false,否则不能查询权限数据
        jdbcRealm.setPermissionsLookupEnabled(true);
        //自定义认证查询语句
        //jdbcRealm.setAuthenticationQuery("authenticationQuery");
        //自定义权限查询语句
        //jdbcRealm.setPermissionsQuery("permissionsQuery");
        //自定义角色查询语句
        //jdbcRealm.setUserRolesQuery("userRolesQuery");
        //1.构建securityManage环境
        /*
         * 默认的查询语句:
        protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
        
        protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";

        protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
*
        protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";*/
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);
        //设置secutityManager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //2.主体提交认证请求
        Subject subject = SecurityUtils.getSubject();
        
        UsernamePasswordToken token =  new UsernamePasswordToken("fusiping","123456");
        subject.login(token);
        
        //结果:isAuthenticated:true
        System.out.println("isAuthenticated:"+subject.isAuthenticated());
        
        subject.checkRole("admin");
        subject.checkPermission("user:delete");
    }
}
 

默认的sql语句:

shiro权限认证框架学习_第1张图片

对应的数据库表:

CREATE TABLE `roles_permissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `permission` varchar(32) NOT NULL COMMENT '权限',
  `role_name` varchar(64) NOT NULL COMMENT '角色',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色-权限';

CREATE TABLE `user_roles` (
  `id` int(11) NOT NULL COMMENT '编号',
  `username` varchar(255) NOT NULL COMMENT '用户名',
  `role_name` varchar(255) NOT NULL COMMENT '角色',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='shiro用户表';


CREATE TABLE `users` (
  `id` int(8) NOT NULL AUTO_INCREMENT COMMENT '主键自增',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(50) NOT NULL COMMENT '密码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='用户表';

自定义Realm:

package com.imooc.shrio.realm;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
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.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**自定义
 * @author fusiping
 * 2018年11月23日
 */
public class CustomRealm extends AuthorizingRealm{
    
    //模拟数据库查询
    Map map = new HashMap(16);
    {
        map.put("fusiping", "123456");
        super.setName("customRealm");
    }

    /* 用来做授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String userName = (String) principals.getPrimaryPrincipal();
        //从数据库或者从缓存中获取角色数据
        Set roles = getRolesByUserName(userName);
        //通过用户从从数据库或者从缓存中获取权限数据
        Set permissions = getPermissionsByUserName(userName);
        SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
        simpleAuthenticationInfo.setStringPermissions(permissions);
        simpleAuthenticationInfo.setRoles(roles);
        return simpleAuthenticationInfo;
    }

    /**模拟从数据库或缓存中获取权限数据
     * @param userName
     * @return
     */
    private Set getPermissionsByUserName(String userName) {
        Set permissions = new HashSet();
        permissions.add("user:delete");
        permissions.add("user:add");
        return permissions;
    }

    /**模拟数据查询
     * @param userName
     * @return
     */
    private Set getRolesByUserName(String userName) {
        Set roles = new HashSet();
        roles.add("admin");
        roles.add("user");
        return roles;
    }

    /* 用来做认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //1.从主体传过来的认证信息中,获取用户名
        String userName = (String) token.getPrincipal();
        
        //2.通过用户名找到数据库中获取凭证
        String password = getPasswordByUserName(userName);
        if (password == null) {
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("fusiping",password,"customRealm");
        return authenticationInfo;
    }

    /**模拟数据库查询凭证
     * @param userName
     * @return
     */
    private String getPasswordByUserName(String userName) {
        return map.get(userName);
    }
    
    
}
 

 测试类CustomRealmTest :

package com.imooc.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

import com.imooc.shrio.realm.CustomRealm;

/**测试
 * @author fusiping
 * 2018年11月23日
 */
public class CustomRealmTest {

    @Test
    public  void testCustomRealm() {
        //自定义
        CustomRealm customRealm = new CustomRealm();
        //1.构建securityManage环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);
        //设置secutityManager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //2.主体提交认证请求
        Subject subject = SecurityUtils.getSubject();
        
        UsernamePasswordToken token =  new UsernamePasswordToken("fusiping","123456");
        subject.login(token);
        
        //结果:isAuthenticated:true
        System.out.println("isAuthenticated:"+subject.isAuthenticated());
        
        subject.checkRole("admin");
        subject.checkPermission("user:delete");
    }
}
 

 

shiro加密:

shiro散列配置:

1 hashedCreadentialsMatcher

2 自定义Realm中使用散列

3 盐的使用 

package com.imooc.shrio.realm;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
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.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**自定义
 * @author fusiping
 * 2018年11月23日
 */
public class CustomRealm extends AuthorizingRealm{
    
    //模拟数据库查询
    Map map = new HashMap(16);
    {
        map.put("fusiping", "cc2bf701edeca9268997bab3f5b6527d");//123456,Md5加盐“fusiping”,加密后e10adc3949ba59abbe56e057f20f883e
        super.setName("customRealm");
    }

    /* 用来做授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String userName = (String) principals.getPrimaryPrincipal();
        //从数据库或者从缓存中获取角色数据
        Set roles = getRolesByUserName(userName);
        //通过用户从从数据库或者从缓存中获取权限数据
        Set permissions = getPermissionsByUserName(userName);
        SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
        simpleAuthenticationInfo.setStringPermissions(permissions);
        simpleAuthenticationInfo.setRoles(roles);
        return simpleAuthenticationInfo;
    }

    /**模拟从数据库或缓存中获取权限数据
     * @param userName
     * @return
     */
    private Set getPermissionsByUserName(String userName) {
        Set permissions = new HashSet();
        permissions.add("user:delete");
        permissions.add("user:add");
        return permissions;
    }

    /**模拟数据查询
     * @param userName
     * @return
     */
    private Set getRolesByUserName(String userName) {
        Set roles = new HashSet();
        roles.add("admin");
        roles.add("user");
        return roles;
    }

    /* 用来做认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //1.从主体传过来的认证信息中,获取用户名
        String userName = (String) token.getPrincipal();
        
        //2.通过用户名找到数据库中获取凭证
        String password = getPasswordByUserName(userName);
        if (password == null) {
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("fusiping",password,"customRealm");
        //识别加盐
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("fusiping"));
        return authenticationInfo;
    }

    /**模拟数据库查询凭证
     * @param userName
     * @return
     */
    private String getPasswordByUserName(String userName) {
        return map.get(userName);
    }
    
    public static void main(String[] args) {
        //加盐:“fusiping”
        Md5Hash md5Hash = new Md5Hash("123456","fusiping");
        System.out.println(md5Hash.toString());
    }
    
}
 

测试:

package com.imooc.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

import com.imooc.shrio.realm.CustomRealm;

/**测试
 * @author fusiping
 * 2018年11月23日
 */
public class CustomRealmTest {

    @Test
    public  void testCustomRealm() {
        //自定义
        CustomRealm customRealm = new CustomRealm();
        //1.构建securityManage环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);
        
        //加密
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        //加密次数
        matcher.setHashIterations(1);
        customRealm.setCredentialsMatcher(matcher);
        
        //设置secutityManager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //2.主体提交认证请求
        Subject subject = SecurityUtils.getSubject();
        
        UsernamePasswordToken token =  new UsernamePasswordToken("fusiping","123456");
        subject.login(token);
        
        //结果:isAuthenticated:true
        System.out.println("isAuthenticated:"+subject.isAuthenticated());
        
        subject.checkRole("admin");
        subject.checkPermission("user:delete");
    }
}
 

shiro+spring整合:

package com.fsp.shiro.realm;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
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.SimpleAuthenticationInfo;
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.apache.shiro.util.ByteSource;

public class CustomRealm extends AuthorizingRealm {

	//模拟数据库查询
		Map map = new HashMap(16);
		{
			map.put("fusiping", "cc2bf701edeca9268997bab3f5b6527d");//123456,Md5加盐“fusiping”,加密后e10adc3949ba59abbe56e057f20f883e
			super.setName("customRealm");
		}

		/* 用来做授权
		 * @param principals
		 * @return
		 */
		@Override
		protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
			String userName = (String) principals.getPrimaryPrincipal();
			//从数据库或者从缓存中获取角色数据
			Set roles = getRolesByUserName(userName);
			//通过用户从从数据库或者从缓存中获取权限数据
			Set permissions = getPermissionsByUserName(userName);
			SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
			simpleAuthenticationInfo.setStringPermissions(permissions);
			simpleAuthenticationInfo.setRoles(roles);
			return simpleAuthenticationInfo;
		}

		/**模拟从数据库或缓存中获取权限数据
		 * @param userName
		 * @return
		 */
		private Set getPermissionsByUserName(String userName) {
			Set permissions = new HashSet();
			permissions.add("user:delete");
			permissions.add("user:add");
			return permissions;
		}

		/**模拟数据查询
		 * @param userName
		 * @return
		 */
		private Set getRolesByUserName(String userName) {
			Set roles = new HashSet();
			roles.add("admin");
			roles.add("user");
			return roles;
		}

		/* 用来做认证
		 * @param token
		 * @return
		 * @throws AuthenticationException
		 */
		@Override
		protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

			//1.从主体传过来的认证信息中,获取用户名
			String userName = (String) token.getPrincipal();
			
			//2.通过用户名找到数据库中获取凭证
			String password = getPasswordByUserName(userName);
			if (password == null) {
				return null;
			}
			SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("fusiping",password,"customRealm");
			//识别加盐
			authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("fusiping"));
			return authenticationInfo;
		}

		/**模拟数据库查询凭证
		 * @param userName
		 * @return
		 */
		private String getPasswordByUserName(String userName) {
			return map.get(userName);
		}
}

controller:

package com.fsp.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
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.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fsp.controller.req.UserModel;

@Controller
public class UserController {

	@RequestMapping(value="/subLogin",method = RequestMethod.POST,produces = "application/json;charset=utf-8")
	@ResponseBody
	public String subLogin(UserModel userModel) {
		Subject subject = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(userModel.getUsername(),userModel.getPassword());
		try {
			subject.login(token);
		} catch (AuthenticationException e) {
			return "登陆异常:"+e.getMessage();
		}
		
		return "登陆成功";
	}
	
	
}

 userModel:

package com.fsp.controller.req;

import lombok.Getter;
import lombok.Setter;

/**登陆接收model
 * @author fusiping
 * 2018年11月23日
 */
@Getter
@Setter
public class UserModel {
	
	private String username;
	private String password;
	

}

 配置文件:

web.xml:


         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="
            http://java.sun.com/xml/ns/javaee
            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
   

   
        shiroFilter
        /*
   

    
      
              contextConfigLocation
              classpath*:spring/spring.xml
      

      
      
          org.springframework.web.context.ContextLoaderListener
      

      
      
          org.springframework.web.context.request.RequestContextListener
      

    
    
        springServlet
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocation
            classpath*:spring/springmvc.xml
        

        1
    

    
        springServlet
        /
    

spring.xml:


    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd"
    default-lazy-init="true">

    Shiro Configuration
    
   
   
       
       
       
       
           
       

   

    
   
   
       
           
                /login.html = anon
                /subLogin = anon
                /subLogin2 = anon
                /* = authc
           

       

   

    
   
   
       
   

    
   
        
   

    
   
   
        
        
   

 

springmvc.xml:


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/mvc  http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"
    default-lazy-init="true">
    
   
   
   
   
 

login.html:





Insert title here



    用户名:

    密码:

    


shiro集成spring从数据库获取数据

spring-dao.xml:


    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.0.xsd">
    
   
           
           
           
   

   
   
           
   

spring.xml


    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd"
    default-lazy-init="true">

   
   
    
   
   
       
       
       
       
       
           
       

   

    
   
   
       
           
                /login.html = anon
                /subLogin = anon
                /* = authc
           

       

   

    
   
   
       
   

    
   
        
   

    
   
   
        
        
   

CustomRealm:

package com.fsp.shiro.realm;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
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.SimpleAuthenticationInfo;
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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.fsp.dao.UserDao;
import com.fsp.entity.User;

@Component
public class CustomRealm extends AuthorizingRealm {

    @Autowired
    private UserDao userDao;

    /* 用来做授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String userName = (String) principals.getPrimaryPrincipal();
        //从数据库或者从缓存中获取角色数据
        Set roles = getRolesByUserName(userName);
        //通过用户从从数据库或者从缓存中获取权限数据
        Set permissions = new LinkedHashSet();
        for (String role : roles) {
            Set list = getPermissionsByUserName(role);
            permissions.addAll(list);
        }
        SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
        simpleAuthenticationInfo.setStringPermissions(permissions);
        simpleAuthenticationInfo.setRoles(roles);
        return simpleAuthenticationInfo;
    }

    /**模拟从数据库或缓存中获取权限数据
     * @param userName
     * @return
     */
    private Set getPermissionsByUserName(String roleName) {
        List list = userDao.queryPermissionsByUserName(roleName);
        Set permissions = new HashSet(list);
        return permissions;
    }

    /**数据查询角色
     * @param userName
     * @return
     */
    private Set getRolesByUserName(String userName) {
        List list = userDao.queryRolesByUserName(userName);
        Set roles = new HashSet(list);
        return roles;
    }

    /* 用来做认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //1.从主体传过来的认证信息中,获取用户名
        String userName = (String) token.getPrincipal();
        
        //2.通过用户名找到数据库中获取凭证
        String password = getPasswordByUserName(userName);
        if (password == null) {
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName,password,"customRealm");
        //识别加盐,盐值随意
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userName));
        return authenticationInfo;
    }

    /*public static void main(String[] args) {
        //数据源+盐
        Md5Hash md5 = new Md5Hash("123456","fusiping");
        System.out.println(md5.toString());
    }*/
    /**模拟数据库查询凭证
     * @param userName
     * @return
     */
    private String getPasswordByUserName(String userName) {
        User user = userDao.getUserByUserName(userName);
        if (user != null) {
            return user.getPassword();
        }
        return null;
    }
}
 

dao:

package com.fsp.dao;

import java.util.List;

import com.fsp.entity.User;

public interface UserDao {

    User getUserByUserName(String userName);

    List queryRolesByUserName(String userName);

    List queryPermissionsByUserName(String roleName);

}
 

daoImpl:

 

package com.fsp.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;

import com.fsp.dao.UserDao;
import com.fsp.entity.User;

@Component
public class UserDaoImpl implements UserDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    /* 数据库查询密码
     * @param userName
     * @return
     */
    public User getUserByUserName(String userName) {
        String sql = "select username, password from users where username = ?";
        List list = jdbcTemplate.query(sql, new String[] {userName}, new RowMapper() {
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                User user = new User();
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                return user;
            }
        });
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    /* 数据库查询角色
     * @param userName
     * @return
     */
    public List queryRolesByUserName(String userName) {
        String sql = "select role_name from user_roles where username = ?";
        return jdbcTemplate.query(sql, new String[] {userName}, new RowMapper() {
            public String mapRow(ResultSet rs, int rowNum) throws SQLException {
                return rs.getString("role_name");
            }
        });
    }

    /* 根据角色返回权限数据
     * @param roleName
     * @return
     */
    public List queryPermissionsByUserName(String roleName) {
        String sql = "select permission from roles_permissions where role_name = ?";
        return jdbcTemplate.query(sql, new String[] {roleName}, new RowMapper() {
            public String mapRow(ResultSet rs, int rowNum) throws SQLException {
                return rs.getString("permission");
            }
        });
    }

}
 

controller:

package com.fsp.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
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.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fsp.controller.req.UserModel;

@Controller
public class UserController {

    @RequestMapping(value="/subLogin",method = RequestMethod.POST,produces = "application/json;charset=utf-8")
    @ResponseBody
    public String subLogin(UserModel userModel) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(userModel.getUsername(),userModel.getPassword());
        try {
            subject.login(token);
        } catch (AuthenticationException e) {
            return "登陆异常:"+e.getMessage();
        }
        
        if (subject.hasRole("admin")) {
            subject.checkPermission("user:delete");
            return "有admin权限";
            
        }
        return "无admin权限";
    }
    
    
}
 

通过注解配置权限:

pom.xml添加:

    
      
          org.aspectj
          aspectjweaver
          1.8.9
      

springmvc.xml添加:

 
   
   
   
   
        
   
 

controller添加:

/**当前主题必须具备amdin觉得才可以访问
     * @return
     */
    @RequiresRoles("admin")
    @RequestMapping(value="/testRole",method=RequestMethod.GET)
    @ResponseBody
    public String testRole() {
        return "testRole success";
    }
    
    
    /**推荐使用的方法
     * @return
     */
    @RequiresPermissions("user:delete")
    @RequestMapping(value="/testRole1",method=RequestMethod.GET)
    @ResponseBody
    public String testRole1() {
        return "testRole success";
    }

shrio内置过滤器:

认证过滤器:anon,authBasic,authc,user,logout 

anon:不需要任何认证,直接访问

authBasic:HTTP基本认证

authc:需要认证之后才可以访问

user:需要当前存在用户才能访问

logout;退出、

授权过滤器:perms,roles,ssl,port

perms:需要具备相关权限才可以访问

roles:跟perms差不多,在[]里面满足的相关权限

ssl:https协议

port:[]里面的端口

 

 

自定义filter:

package com.fsp.filter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;

/**自动一授权,如果包含其中一个权限,则执行
 * @author fusiping
 * 2018年11月27日
 */
public class RoleOrFilter extends AuthorizationFilter {

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception {
        Subject subject = getSubject(request, response);
        String[] roles = (String[]) mappedValue;
        if (roles == null || roles.length == 0 ) {
            return true;
        }
        for (String role : roles) {
            if (subject.hasRole(role)) {
                return true;
            }
        }
        return false;
    }
    
}
 

spring.xml:

注入自定义bean


    

 


    
        
        
        
       
        
        	
        		
        	
        
        
            
        
    

 


    
        
            
                /login.html = anon
                /subLogin = anon
                /testRole = roles["admin","admin1"]  //roles必须包含里面两个角色才能执行
                /testRole1 = rolesOr["admin","admin1"] //rolesOr包含其中一个角色就可以执行
                /* = authc
            
        
    

controller:

 

/**roles["admin","admin1"]  //roles必须包含里面两个角色才能执行
	 * @return
	 */
	@RequestMapping(value="/testRole",method=RequestMethod.GET)
	@ResponseBody
	public String testRole() {
		return "testRole success";
	}
	
	
	/**rolesOr["admin","admin1"] //rolesOr包含其中一个角色就可以执行
	 * @return
	 */
	@RequestMapping(value="/testRole1",method=RequestMethod.GET)
	@ResponseBody
	public String testRole1() {
		return "testRole success";
	}

shiro会话管理

shiro session管理

sessionmanager,sessionDAO

Redis实现session共享

redis实现Session共享存在的问题

引入maven依赖:


        
            redis.clients
            jedis
            2.8.0
        

spring.xml配置文件添加:


    
        
    

    
    
    

 
   
       
       
   

RedisSessionDao:

package com.fsp.session;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.SerializationUtils;

import com.fsp.util.JedisUtil;

/**
 * @author fusiping
 * 2018年11月27日
 */
public class RedisSessionDao extends AbstractSessionDAO{
    
    @Autowired
    private JedisUtil jedisUtil;
    
    //前缀
    private final String SHIRO_SESSION_PREFIX = "fsp-session";
    
    //前缀+key组成的key
    private byte[] getKey(String key) {
        return (SHIRO_SESSION_PREFIX + key).getBytes();
    }
    
    /**保存session
     * @param session
     */
    private void savaSession(Session session) {
        if (session != null && session.getId() != null) {
            byte[] key = getKey(session.getId().toString());
            byte[] value = SerializationUtils.serialize(session);
            jedisUtil.set(key,value);
            jedisUtil.expire(key,600);
        }
    }
    /* 创建sessionID
     * @param session
     * @return
     */
    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        //捆绑session,sessionId
        assignSessionId(session, sessionId);
        savaSession(session);
        return sessionId;
    }
    
    @Override
    protected Session doReadSession(Serializable sessionId) {
        System.out.println("read session");
        if (sessionId == null) {
            return null;
        }
        byte[] key = getKey(sessionId.toString());
        byte[] value = jedisUtil.get(key);
        //反序列化成json对象
        return (Session) SerializationUtils.deserialize(value);
    }

    /* 更新session
     * @param session
     * @throws UnknownSessionException
     */
    public void update(Session session) throws UnknownSessionException {
        savaSession(session);
    }

    /* 删除session
     * @param session
     */
    public void delete(Session session) {
        if (session == null || session.getId() == null) {
            return ;
        }
        byte[] key = getKey(session.getId().toString());
        jedisUtil.del(key);
    }

    /* 获取正在活动的session
     * @return
     */
    public Collection getActiveSessions() {
        Set keys = jedisUtil.keys(SHIRO_SESSION_PREFIX);
        Set sessions = new HashSet();
        if (CollectionUtils.isEmpty(keys)) {
            return sessions;
        }
        for (byte[] key : keys) {
            Session session = (Session) SerializationUtils.deserialize(jedisUtil.get(key));
            sessions.add(session);
        }
        return sessions;
    }

    

    

}
 

添加spring-redis.xml:


    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.0.xsd">
    
   
           
           
           
   

   
   
 

spring.xml引入spring-resdis.xml:

 

 JedisUtil工具类:

package com.fsp.util;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.val;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**redis访问工具包
 * @author fusiping
 * 2018年11月27日
 */
@Component
public class JedisUtil {

    @Autowired
    private JedisPool jedisPool;
 
    private Jedis getResource() {
        return jedisPool.getResource();
    }
    
    public byte[] set(byte[] key, byte[] value) {
        Jedis jedis = getResource();
        try {
            jedis.set(key, value);
            return value;
        } finally {
            jedis.close();
        }
    }

    public void expire(byte[] key, int i) {
        Jedis jedis = getResource();
        try {
            jedis.expire(key, i);
        } finally {
            jedis.close();
        }
    }

    public byte[] get(byte[] key) {
        Jedis jedis = getResource();
        try {
            return jedis.get(key);
        } finally {
            jedis.close();
        }
    }

    public void del(byte[] key) {
        Jedis jedis = getResource();
        try {
            jedis.del(key);
        } finally {
            jedis.close();
        }
    }

    public Set keys(String sHIRO_SESSION_PREFIX) {
        Jedis jedis = getResource();
        try {
            //转成二进制
            return jedis.keys((sHIRO_SESSION_PREFIX + "*").getBytes());
        } finally {
            jedis.close();
        }
    }
    
    
    
}
 

结果:

 shiro权限认证框架学习_第2张图片

注意:必须先启动redis:运行命令:

 shiro权限认证框架学习_第3张图片

但是每次请求都会调用多次session,需要优化性能:

shiro权限认证框架学习_第4张图片

所以自定义 SessionManager:

package com.fsp.session;

import java.io.Serializable;

import javax.servlet.ServletRequest;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;

/**自定义sessionmanager
 * @author fusiping
 * 2018年11月27日
 */
public class CustomSessionManager extends DefaultWebSessionManager {
    
    /* 重新retrieveSession
     * 先从request中获取,取不到则从redis,取到后在set到request
     * @param sessionKey
     * @return
     * @throws UnknownSessionException
     */
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        // 1先获取sessionId
        Serializable sessionId = getSessionId(sessionKey);
        ServletRequest request = null;
        //先反对是不是WebSessionKey类型
        if (sessionKey instanceof WebSessionKey) {
            //从sessionkey总获取request
            request = ((WebSessionKey) sessionKey).getServletRequest();
        }
        //如果request != null && sessionId != null
        if (request != null && sessionId != null) {
            //直接从request中获取session
            return (Session) request.getAttribute(sessionId.toString());
        }
        //那么从retrieveSession中获取
        Session session = super.retrieveSession(sessionKey);
        if (request != null && sessionId != null) {
            request.setAttribute(sessionId.toString(), session);
        }
        return session;
    }

}
 

修改spring.xml:


    
        
    
 

 优化sessionManager

package com.fsp.session;

import java.io.Serializable;

import javax.servlet.ServletRequest;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;

/**自定义sessionmanager
 * @author fusiping
 * 2018年11月27日
 */
public class CustomSessionManager extends DefaultWebSessionManager {
    
    /* 重新retrieveSession
     * 先从request中获取,取不到则从redis,取到后在set到request
     * @param sessionKey
     * @return
     * @throws UnknownSessionException
     */
    @Override
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        // 1先获取sessionId
        Serializable sessionId = getSessionId(sessionKey);
        ServletRequest request = null;
        //先反对是不是WebSessionKey类型
        if (sessionKey instanceof WebSessionKey) {
            //从sessionkey总获取request
            request = ((WebSessionKey) sessionKey).getServletRequest();
        }
        //如果request != null && sessionId != null
        if (request != null && sessionId != null) {
            //直接从request中获取session
            Session session = (Session) request.getAttribute(sessionId.toString());
            if (session != null ) {
                return session;
            }
        }
        //那么从retrieveSession中获取
        Session session = super.retrieveSession(sessionKey);
        if (request != null && sessionId != null) {
            request.setAttribute(sessionId.toString(), session);
        }
        return session;
    }

}
 

 优化之后就不用每次都多次调用redis

spring.xml添加:

 
   
       
       
          //shrio session 缓存
   

 


    

 

RedisCacheManager:

 

package com.fsp.cache;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired;

public class RedisCacheManager implements CacheManager{
    
    @Autowired
    private RedisCache redisCache;

    public Cache getCache(String arg0) throws CacheException {
        
        return redisCache;
    }

}
 

RedisCache:

package com.fsp.cache;

import java.util.Collection;
import java.util.Set;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.SerializationUtils;

import com.fsp.util.JedisUtil;
@Component
public class RedisCache implements Cache{
    
    @Autowired
    private JedisUtil jedisUtil;
    
    private final String cache_prefix = "fsp-cache"; 

    private byte[] getKey(K k) {
        if (k instanceof String) {
            return (cache_prefix + k).getBytes();
        }
        return SerializationUtils.serialize(k);
    }
    public void clear() throws CacheException {
        // TODO Auto-generated method stub
        
    }

    public V get(K k) throws CacheException {
        System.out.println("从reids中获取权限数据");
        byte[] value = jedisUtil.get(getKey(k));
        if (value != null ) {
            return (V) SerializationUtils.deserialize(value);
        }
        return null;
    }

    public Set keys() {
        
        return null;
    }

    public V put(K arg0, V arg1) throws CacheException {
        byte[] key = getKey(arg0);
        byte[] value = SerializationUtils.serialize(arg1);
        jedisUtil.set(key, value);
        jedisUtil.expire(key, 600);
        return arg1;
    }

    /* 删除
     * @param arg0
     * @return
     * @throws CacheException
     */
    public V remove(K arg0) throws CacheException {
        byte[] key = getKey(arg0);
        byte[] value = jedisUtil.get(key);
        jedisUtil.del(key);
        if (value != null) {
            return (V) SerializationUtils.deserialize(value);
        }
        return null;
    }

    public int size() {
        // TODO Auto-generated method stub
        return 0;
    }

    public Collection values() {
        // TODO Auto-generated method stub
        return null;
    }

}
 

 记住我功能:

spring.xml:


    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd"
    default-lazy-init="true">

   
   
   
    
   
   
       
       
       
       
       
            
                
            

       

       
           
       

   

    
   
   
       
           
                /login.html = anon
                /subLogin = anon
                /testRole = roles["admin","admin1"]
                /testRole1 = rolesOr["admin","admin1"]
               
                /* = authc
           

       

   

    
   
   
    
   
   
       
       
       
       
   

    
   
        
   

    
   
   
        
        
   

    
    
        
    

    
    
    
    
    
    
    
        
    

    
    
        
        
    

    

loginController:

@RequestMapping(value="/subLogin",method = RequestMethod.POST,produces = "application/json;charset=utf-8")
	@ResponseBody
	public String subLogin(UserModel userModel) {
		Subject subject = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(userModel.getUsername(),userModel.getPassword());
		try {
			token.setRememberMe(userModel.isRememberMe());
			subject.login(token);
		} catch (AuthenticationException e) {
			return "登陆异常:"+e.getMessage();
		}
		
		if (subject.hasRole("admin")) {
			subject.checkPermission("user:delete");
			return "有admin权限";
			
		}
		return "无admin权限";
	}

login.xml:

 





Insert title here



    用户名:

    密码:

    记住我

    


 

你可能感兴趣的:(shiro框架)