Shiro的总结和使用。搭配ssm框架使用。

学了好几天了,一直说做笔记做笔记,总感觉没时间其实是拖延时间而已。以后学习之后都会总结。

1.导jar包

	
                <!-- shiro权限管理版本-->
    	        <shiro.version>1.2.2</shiro.version>



                <!-- shiro权限管理的jar包 -->
		 <dependency>
			  <groupId>org.apache.shiro</groupId>
			  <artifactId>shiro-spring</artifactId>
  		</dependency>
  		<!-- shiro核心包 -->
		 <dependency>
			  <groupId>org.apache.shiro</groupId>
			  <artifactId>shiro-core</artifactId>
		 </dependency>
		  <dependency>
			   <groupId>org.apache.shiro</groupId>
			   <artifactId>shiro-ehcache</artifactId>
		  </dependency>
		  <dependency>
			   <groupId>org.apache.shiro</groupId>
			   <artifactId>shiro-web</artifactId>
		  </dependency>
		  <dependency>
			   <groupId>org.apache.shiro</groupId>
			   <artifactId>shiro-quartz</artifactId>
		  </dependency>

2.配置shiro拦截器在项目的web.xml中配置例如


	<!-- shiro拦截器的配置 -->
	<filter>
		<filter-name>shiroFileter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>shiroFileter</filter-name>
		<!-- 使用[/*]匹配所有请求,保证所有的可控请求都经过Shiro的过滤 --> 
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	

3.先自定义Realm毕竟登录验证和权限校验都要在这里面进行。我这里只做了授权没有做认证,也许是懒把。

public class ShiroRealm  extends AuthorizingRealm {
	@Autowired
	private indexservice indexservice;
	/*
	 * 做授权
	 *授权查询回调函数, 进行鉴权但缓存中无用户的授权信
	 *息时调用,负责在应用程序中决定用户的访问控制的方法(non-Javadoc)
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
                //说一下思路把,得到这个用户名,去数据库或者缓存里面查询组装set集合返回。
                String username=(String) getAvailablePrincipal(principals);
		// TODO Auto-generated method stub
		//返回数据
		System.out.println("doGetAuthorizationInfo");
		SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
		//authorizationInfo.setObjectPermissions(objectPermissions);设置权限集合
		//authorizationInfo.setRoles(roles);设置角色
		return authorizationInfo;
	}
	/*
	 * 做认证使用的方法
	 * 获取用户角色信息和权限信息,一代后续进行访问控制
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// TODO Auto-generated method stub
		String username =(String) token.getPrincipal();//得到用户名
		//通过用户名获取密码
		String password=getPasswordByUserName(username);
		 SimpleAuthenticationInfo authenticationInfo =new SimpleAuthenticationInfo(username,password,getName());
		 authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("田"));//加盐
		return authenticationInfo;
	}
	private String getPasswordByUserName(String username) {
		// TODO Auto-generated method stub 
		System.out.println("从数据查询-----------------------");
		return indexservice.getUserBypassword(username);
	}

}

4.配置shiro,我是新建了一个applicationContext-shiro.xml来配置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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
	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.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
      	http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
		<!-- 
	   loginUrl:没有登录的用户请求需要登录的页面时自动跳转到登录页面。 
       unauthorizedUrl:没有权限默认跳转的页面,登录的用户访问了没有被授权的资源自动跳转到的页面。
	     其他的一些配置,如下:   
	   successUrl:登录成功默认跳转页面,不配置则跳转至”/”,可以不配置,直接通过代码进行处理。
	   securityManager:这个属性是必须的,配置为securityManager就好了。
	   filterChainDefinitions:配置过滤规则,从上到下的顺序匹配。
		 -->
		 <context:component-scan base-package="com.taotao.controller.shirocontroller"></context:component-scan>
		
		 <!--创建shiroFilter对象-->
		<bean id="shiroFileter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
			<property name="securityManager" ref="securityManager"></property>
			<property name="loginUrl" value="/index.action"></property>
			<property name="unauthorizedUrl" value="/403"></property>
			<property name="filterChainDefinitions">
			 <!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 -->  
			 <!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 -->  
			 <!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->  
				<value>
					/index.action=anon
					/shiroindext.action=anon
					/*=authc
				</value>
			</property>
		</bean>
	     <!--创建shiro需要的对象-->   
	     <!--创建 securityManager 对象-->  
	       <bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager">   
	            <property name="realm" ref="realm"/> 
	            <property name="sessionManager" ref="sessionManager"></property>
	            <property name="cacheManager" ref="cacheManager"></property>
	            <property name="rememberMeManager" ref="rememberMeManager"></property>
	       </bean>    
	       <!--创建自定义realm对象-->    
	       <bean class="com.taotao.controller.shirocontroller.ShiroRealm" id="realm">   
	              <property name="credentialsMatcher" ref="credentialsMatcher"/> 
	       </bean>    
	       <!--加密管理器对象-->   
	       <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher" id="credentialsMatcher">
               <property name="hashAlgorithmName" value="md5"/> 
               <!-- 加密次数 -->
               <property name="hashIterations" value="2"/>    
	       </bean>
	       <!-- 创建自定义sessionManager 解决问题多次去redis查询数据    session管理 -->
	       <bean id="sessionManager" class="com.taotao.controller.shirocontroller.CustomSessionManager">
	       		<property name="sessionDAO" ref="redisSessionDao"></property>
	       </bean>
	       <bean id="redisSessionDao" class="com.taotao.controller.shirocontroller.RedisSessionDao">
	       </bean>
	       
	       <bean class="com.taotao.controller.shirocontroller.RedisCacheManage" id="cacheManager">
	       </bean>
 
	       <!-- shiro 自动登录配置-->
	       <bean class="org.apache.shiro.web.mgt.CookieRememberMeManager" id="rememberMeManager">
	       		<property name="cookie" ref="cookie"></property>
	       </bean>
	       <bean id="cookie" class="org.apache.shiro.web.servlet.SimpleCookie">
	       		<constructor-arg value="rememberMe"></constructor-arg>
	       		<!-- 设置登录超时时间 -->
	       		<property name="maxAge" value="200000"></property>
	       		<property name="httpOnly" value="true" />
	       </bean>
</beans>

5.applicationContext-shiro.xml这个配置文件之中有id="sessionManager"这个是做session管理的一个类本来shiro自带一个类,但是他们看视频说,这个类在查询session的时候会多次查找会导致性能下降,确实有这个问题。


public class CustomSessionManager extends DefaultWebSessionManager {
    /**
     * 重写方法,优先从request对象中读取session,减轻redis压力
     * @param sessionKey
     * @return
     * @throws UnknownSessionException
     */
    @Override
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        //取到sessionId
        Serializable sessionId = getSessionId(sessionKey);
        ServletRequest request = null;
        //获取request
        if (sessionKey instanceof WebSessionKey){
            request = ((WebSessionKey) sessionKey).getServletRequest();
        }
        //获取session
        Session session = null;
        if (request != null && sessionId != null){
            session = (Session) request.getAttribute(sessionId.toString());
            if (session != null){
                return  session;
            }
        }
        session = super.retrieveSession(sessionKey);
        if (request != null && sessionId != null) {
            request.setAttribute(sessionId.toString(), session);
        }
        return session;
    }

}

6.applicationContext-shiro.xml这个配置文件之中有id="redisSessionDao"这个类这是做session缓存的一个类。


/**
 *  AbstractSessionDAO 提供了 SessionDAO 的基础实现,如生成会话ID等
 * @ClassName: RedisSessionDao
 * @Description: 
 * @author 14729
 * @date 2020年1月9日
 *
 */
public class RedisSessionDao extends AbstractSessionDAO {
	@Autowired
	private JedisClientPool jedis;
	/**
     * 自定义生成sessionId时加上前缀。
     */
    private final String SHIRO_SESSION_PREFIX = "shiro-session:";
    /**
     * @param key
     * @return
     */
    private byte[] getKey(String key) {
    	 return (SHIRO_SESSION_PREFIX + key).getBytes();
    }

    public void saveSession(Session session) {
    	if(session!=null&&session.getId()!=null) {
    	    byte[] value = SerializationUtils.serialize(session);
    		jedis.setbyte(getKey(session.getId().toString()),value);
    		jedis.expirebyte(getKey(session.getId().toString()),1000);
    	}
    }
	@Override
	public void update(Session session) throws UnknownSessionException {
		// TODO Auto-generated method stub
		 saveSession(session);
	}
	@Override
	public void delete(Session session) {
		if(session!=null&& session.getId()!=null) {
			jedis.delbyte(getKey(session.getId().toString()));
		}
	}
	/*
	 * 获取所有的session
	 * (non-Javadoc)
	 * @see org.apache.shiro.session.mgt.eis.SessionDAO#getActiveSessions()
	 */
	@Override
	public Collection<Session> getActiveSessions() {
		Set<Session> sessions=new HashSet<Session>();
		Set<String> keys = jedis.keys(SHIRO_SESSION_PREFIX);
		if(CollectionUtils.isEmpty(keys))
			return sessions;
		for (String string : keys) {
			Session session= (Session) SerializationUtils.deserialize(jedis.getbyte(string.getBytes()));
			sessions.add(session);
		}
		return sessions;
	}
	/* 创建session,返回sessionid
	 * @see org.apache.shiro.session.mgt.eis.AbstractSessionDAO#doCreate(org.apache.shiro.session.Session)
	 */
	@Override
	protected Serializable doCreate(Session session) {
		System.out.println("创建ssession给缓存里面保存session");
		Serializable sessionid=generateSessionId(session);//根据session生成sessionId
		assignSessionId(session, sessionid); //将sessionId和session进行捆绑
		saveSession(session); //保存session
		return sessionid;
	}
	 /**
     * 根据sessionId返回session
     *
     * @param sessionId
     * @return
     */
	@Override
	protected Session doReadSession(Serializable sessionId) {
		  if (StringUtils.isEmpty(sessionId)) {
	            return null;
	        }
	        byte[] key = getKey(sessionId.toString());
	        byte[] value = jedis.getbyte(key);
	        if(StringUtils.isEmpty(value))
	        	return null;
	        return (Session) SerializationUtils.deserialize(value);
	}
}

7 配置文件中id="cacheManager"这个类是做会话管理的。


public class RedisCacheManage implements CacheManager{
	@Autowired
	private RedisCache<?, ?> redisCache;
	@Override
	public <K, V> Cache<K, V> getCache(String name) throws CacheException {
		// TODO Auto-generated method stub
		return  (Cache<K, V>) redisCache;
	}

}

8.RedisCacheManage这个类里面的 RedisCache是做会话缓存管理的

@Component
public class RedisCache<K,V> implements Cache<K,V>{
	private final String CACHE_PREFIX="cache-session";
	@Autowired
	private JedisClientPool jePool;
	
	private byte[] getKey(K k) {
		if(k instanceof String) {
			return (CACHE_PREFIX+k).getBytes();
		}
		return SerializationUtils.serialize(k);
	}
	
	@Override
	public V put(K key, V val) {
		System.out.println("");

		byte[] bs = getKey(key);
		byte[] value=SerializationUtils.serialize(val);
		jePool.setbyte(bs, value);
		jePool.expirebyte(bs, 1000);
		return val;
	}

	@Override
	public V get(K key) {
		byte[] bs = jePool.getbyte(getKey(key));
		if(bs!=null)
			return (V) SerializationUtils.deserialize(bs);
		return null;
	}

	@Override
	public V remove(K key) {
		byte[] bs = getKey(key);
		byte [] value=jePool.getbyte(bs);
		jePool.delbyte(bs);
		if(value==null)
			return null;
		return  (V) SerializationUtils.deserialize(value);
	}

	@Override
	public void clear() {
		// TODO Auto-generated method stub
		
	}

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

	@Override
	public Set<K> keys() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Collection<V> values() {
		// TODO Auto-generated method stub
		return null;
	}

}

9,上面JedisClientPool 这个类是对redis做一些增删改查的。这个类就不给了,其实就是对JedisPool这类进行操作。

10.基本都配置完成了。接着定义一个Controller

@Controller
public class shiroController {
	@Autowired
	private RedisSessionDao redisSessionDao;
	
	@RequestMapping(value="/index")
	public String shiroIndex() {
		return "NewFile";
	}
	@RequestMapping(value="/shiroindext",method= { RequestMethod.GET, RequestMethod.POST })
	public String subLogin(User user) {
		  Subject subject = SecurityUtils.getSubject();
                    
		  if (!subject.isAuthenticated() && subject.isRemembered()) {//判断cookie是否过期。在配置文件里面有配置,自动登录
			  System.out.println("没有使用cookie登录");
			  UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
			  try {
				  System.err.println("获取的值是"+user.isRememberMe());
				  	token.setRememberMe(user.isRememberMe());
		            subject.login(token);
		        } catch (AuthenticationException e) {
		            return "nopower";
		        }
			 // subject.checkRole("admin1");
			return "Main";
		  }else {
			  System.out.println("使用cookie登录=======》");
			  return "Main";
		}
	}
}

11.q

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="shiroindext.action" method="post">
<a>来了</a>
	 用户名:<input type="text" name="username"><br/>
	 密码:<input type="password" name="password"><br>
	 是否选中<input type="checkbox" name="rememberMe"><br>
	 
	<input  type="submit" value="Submit">
</form> 
</body>
</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值