先准备一个 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 取出来也要一样的,如果有更好的方法,欢迎指教