springboot+shiro,两个项目完全不同,达成session共享

先准备一个 shiroConfig

package com.med.common.config;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.med.common.shiroRealm.MyShiroRealm;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;

@Configuration
public class ShiroConfig {
	
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager")DefaultWebSecurityManager securityManager) {
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //拦截器.
        Map filterChainDefinitionMap = new LinkedHashMap();
        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/staticMed/**", "anon");
        filterChainDefinitionMap.put("/medCaseManagementBack", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        //:这是一个坑呢,一不小心代码就不好使了;
        //
        filterChainDefinitionMap.put("/power/**", "authc");
        filterChainDefinitionMap.put("/power/user/add", "perms[user:add]");
        filterChainDefinitionMap.put("/*", "authc");
       
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/power/login");
        
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/power/index");

        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/power/unAuth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
    
    //创建Realm,配置自定义的权限登录器 
    @Bean(name="userRealm")    
    public MyShiroRealm getUserRealm(){
    	MyShiroRealm myShiroRealm = new MyShiroRealm();
    	myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myShiroRealm;    
        
    }
    
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
    
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
    	HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    	hashedCredentialsMatcher.setHashAlgorithmName("MD5"); // 加密方式
    	hashedCredentialsMatcher.setHashIterations(888); // 加密次数
    	hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
    	return hashedCredentialsMatcher;
    }
    
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    	AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    	attributeSourceAdvisor.setSecurityManager(securityManager);
    	return attributeSourceAdvisor;
    }
    
    
}

之后给一个属于自己的验证

package com.med.common.shiroRealm;
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.stereotype.Component;

import com.ky.entity.power.ComUser;

@Component("authorizer")
public class MyShiroRealm extends AuthorizingRealm {
    
    /*@Autowired
    private ComUserService comUserService;*/
    
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        ComUser user  = (ComUser)principals.getPrimaryPrincipal();
        //System.out.println("User:"+user.toString()+" roles count:"+user.getRoles().size());
        /*for(Role role:user.getRoles()){
            authorizationInfo.addRole(role.getId());
            role=roleService.getRoleById(role.getId());
            System.out.println("Role:"+role.toString());
            for(Permission p:role.getPermissions()){
                System.out.println("Permission:"+p.toString());
                authorizationInfo.addStringPermission(p.getCode());
            }
        }*/
        System.out.println("权限配置-->authorizationInfo"+authorizationInfo.toString());
        return authorizationInfo;
    }

    /*主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        System.out.println("MyShiroRealm.doGetAuthenticationInfo()");
        //获取用户的输入的账号.
        String usercode = (String)token.getPrincipal();
        
        //通过username从数据库中查找 User对象
        ComUser user = null;
        if(user == null){
            return null;
        }
        // 盐值
        ByteSource cByteSource = ByteSource.Util.bytes(user.getUser_code());
        
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
        		user, //用户
        		user.getPassword(), //密码
        		cByteSource,
                getName()  //realm name
        );
        return authenticationInfo;
    }

}

配一个SessionManager

package com.med.common.shiroRealm;

import java.io.Serializable;

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

import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SessionContext;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.med.common.dao.RedisSessionDao;

@Configuration
public class ShiroSessionManager extends DefaultWebSessionManager {
	
	@Value("${shiro.jessionid}")
	private String jessionId;
    
    private static final String AUTH_TOKEN = "authToken";

    private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
	
	@Bean
	public RedisSessionDao getRedisSessionDao() {
		return new RedisSessionDao();
	}
	
	@Bean(name = "sessionManager")
	public DefaultWebSessionManager defaultWebSessionManager() {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setGlobalSessionTimeout(43200000);
		sessionManager.setDeleteInvalidSessions(true);
		
		sessionManager.setSessionDAO(getRedisSessionDao());
		sessionManager.setSessionValidationSchedulerEnabled(true);
		sessionManager.setDeleteInvalidSessions(true);
		sessionManager.setSessionIdCookie(getSessionIdCookie());
		return sessionManager;
	}
	
	@Bean(name = "sessionDao")
	public EnterpriseCacheSessionDAO sessionDao() {
	    EnterpriseCacheSessionDAO sessionDao = new EnterpriseCacheSessionDAO();
	    sessionDao.setActiveSessionsCacheName("shiro-activeSessionCache");
	    sessionDao.setSessionIdGenerator(new UUIDSessionIdGenerator());
	    return sessionDao;
	}

    // 配置核心安全事务管理器
    @Bean(name="defaultWebSecurityManager")    //创建DefaultWebSecurityManager    
    public DefaultWebSecurityManager getDefaultWebSecurityManager(
    		@Qualifier("userRealm")MyShiroRealm userRealm){        
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
    	manager.setRealm(userRealm);
    	manager.setSessionManager(defaultWebSessionManager());
    	return manager;
    }
    
    @Bean(name = "sessionIdCookie")
    public SimpleCookie getSessionIdCookie() {
    	SimpleCookie simpleCookie = new SimpleCookie(jessionId);
    	return simpleCookie;
    }
    
    @Override
    protected void onStart(Session session, SessionContext context) {
    	// TODO Auto-generated method stub
    	super.onStart(session, context);
    }

    /**
     * 获取sessionId,原本是根据sessionKey来获取一个sessionId
     * 重写的部分多了一个把获取到的token设置到request的部分。这是因为app调用登陆接口的时候,是没有token的,登陆成功后,产生了token,我们把它放到request中,返回结
     * 果给客户端的时候,把它从request中取出来,并且传递给客户端,客户端每次带着这个token过来,就相当于是浏览器的cookie的作用,也就能维护会话了
     * @param request
     * @param response
     * @return
     */
    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        //获取请求头中的 AUTH_TOKEN 的值,如果请求头中有 AUTH_TOKEN 则其值为sessionId。shiro就是通过sessionId 来控制的
    	String sessionId = WebUtils.toHttp(request).getHeader(AUTH_TOKEN);
        if (sessionId.equals("")){
            //如果没有携带id参数则按照父类的方式在cookie进行获取sessionId
            return super.getSessionId(request, response);

        } else {
            //请求头中如果有 authToken, 则其值为sessionId
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
            //sessionId
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return sessionId;
        }
    }

}

写一个属于自己生成sessionId的过程

package com.med.common.shiroRealm;

import java.io.Serializable;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

public class UUIDSessionIdGenerator implements SessionIdGenerator {
	
	@Override
	public Serializable generateId(Session session) {
		// TODO Auto-generated method stub 
		Serializable id = "123456";
		return id;
	}

	
}

最后把shiro自定义增删改查一写,就行了

package com.med.common.dao;

import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

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.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.med.common.shiroRealm.UUIDSessionIdGenerator;

@Service
public class RedisSessionDao extends AbstractSessionDAO {

	private long expireTime = 1000000;
	
	@Autowired
	private RedisTemplate redisTemplate;
	
	public RedisSessionDao() {
		// TODO Auto-generated constructor stub
		this.setSessionIdGenerator(new UUIDSessionIdGenerator());
	}
	
	public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) {
		// TODO Auto-generated constructor stub
		super();
		this.expireTime = expireTime;
		this.redisTemplate = redisTemplate;
	}
	
	// 修改
	@Override
	public void update(Session session) throws UnknownSessionException {
		// TODO Auto-generated method stub
		if(session == null || session.getId() == null) {
			return;
		}
		redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS );
	}

	// 删除
	@Override
	public void delete(Session session) {
		// TODO Auto-generated method stub
		if(null == session) {
			return;
		}
		redisTemplate.opsForValue().getOperations().delete(session.getId());
	}

	// 获取活跃的session,可以用来统计在线人数
	// 如果要实现这个功能,可以在将session加入redis时指定一个session前缀,
	// 统计的时候则使用keys("session-prefix*")的方式来模糊查找redis中所有的session集合
	@Override
	public Collection getActiveSessions() {
		// TODO Auto-generated method stub
		return redisTemplate.keys("*");
	}

	@Override
	protected Serializable doCreate(Session session) {
		// TODO Auto-generated method stub
		Serializable sessionId = this.generateSessionId(session);
		this.assignSessionId(session, sessionId);
		
		redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MICROSECONDS);
		return sessionId;
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		// TODO Auto-generated method stub
		if (sessionId == null) {
			return null;
		}
		
		return (Session) redisTemplate.opsForValue().get(sessionId);
	}
	
	public long getExpireTime() {
		return expireTime;
	}
	
	public void setExpireTime(long expireTime) {
		this.expireTime = expireTime;
	}
	
	public RedisTemplate getRedisTemplate() {
		return redisTemplate;
	}
	
	public void setRedisTemplate(RedisTemplate redisTemplate) {
		this.redisTemplate = redisTemplate;
	}
}

话不多说,最重要的一步是自己设定 sessionId 就是在 sessionDao 中初始化将这句加上

this.setSessionIdGenerator(new UUIDSessionIdGenerator());

其余的步骤可以自己随便玩,完全可以不用按照我的写,这样,两个项目的 sessionId 都一样,那么取出来的对象都是一样的,当然,另一个项目的包名,类名,要和共享的id一模一样,一开始登录的时候,放的是什么 session 取出来也要一样的,如果有更好的方法,欢迎指教

你可能感兴趣的:(springboot+shiro,两个项目完全不同,达成session共享)