之前项目鉴权一直使用的Shiro,那是在Spring MVC里面使用的比较多,而且都是用XML来配置,用Shiro来做权限控制相对比较简单而且成熟,而且我一直都把Shiro的session放在mongodb中,这个比较符合mongodb的设计初衷,而且在分布式项目中mongodb也作为一个中间层,用来很好很方便解决分布式环境下的session同步的问题。
自从SpringBoot问世之后我的项目基本上能用SpringBoot的就会用SpringBoot,用MAVEN做统一集中管理也很方便,虽然SpringBoot也提供了一套权限安全框架Spring Security,但是相对来说还是不是太好用,所以还是用Shiro来的方便一点,SpringBoot集成Shiro要比Spring MVC要简单的多,至少没有一堆XML配置,看起来更清爽,那么接下来我们就开始集成。
第一步必然是在MAVEN中先添加Shiro和mongo的依赖,我用的Shiro版本是
1.2.3
添加依赖:
org.apache.shiro shiro-core${shiro.version} org.apache.shiro shiro-web${shiro.version} org.apache.shiro shiro-spring${shiro.version} org.mongodb mongo-java-driver3.0.0 org.springframework.data spring-data-mongodb1.7.0.RELEASE
然后在application.xml或yml中配置mongodb
spring.data.mongodb.host=127.0.0.1 spring.data.mongodb.port=27017 spring.data.mongodb.database=SHIRO_INFO
配置完成之后我们开始正式写Shiro认证的代码,先自定义一个鉴权realm,继承自AuthorizingRealm
public class ShiroDbRealm extends AuthorizingRealm {
private SystemUserService systemUserService; public ShiroDbRealm() {} public ShiroDbRealm(SystemUserService systemUserService) { this.systemUserService = systemUserService;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = (SimpleAuthorizationInfo) ShiroKit.getShiroSessionAttr("perms"); if (null != info && !CollectionUtils.isEmpty(info.getRoles())
&& !CollectionUtils.isEmpty(info.getStringPermissions())) { return info;
} return null;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String userName = token.getUsername(); if (userName != null && !"".equals(userName)) {
SystemUser key = new SystemUser();
key.setLoginName(token.getUsername());
key.setPassword(String.valueOf(token.getPassword()));
SystemUser user = systemUserService.login(key); if (user != null) {
Subject userTemp = SecurityUtils.getSubject();
userTemp.getSession().setAttribute("userId", user.getId());
userTemp.getSession().setAttribute("userName", user.getUserName()); return new SimpleAuthenticationInfo(user.getLoginName(), user.getPassword(), getName());
}
} return null;
}
}存储session进mongodb的Repository和实现:
public interface ShiroSessionRepository {
void saveSession(Session session);
......
}MongoDBSessionRepository.java
public class MongoDBSessionRepository implements ShiroSessionRepository { private MongoTemplate mongoTemplate; public MongoDBSessionRepository() {} public MongoDBSessionRepository(MongoTemplate mongoTemplate) { this.mongoTemplate = mongoTemplate;
} @Override
public void saveSession(Session session) { if (session == null || session.getId() == null) { return;
}
SessionBean bean = new SessionBean();
bean.setKey(getSessionKey(session.getId()));
bean.setValue(SerializeUtil.serialize(session));
bean.setPrincipal(null);
bean.setHost(session.getHost());
bean.setStartTimestamp(session.getStartTimestamp());
bean.setLastAccessTime(session.getLastAccessTime());
bean.setTimeoutTime(getTimeoutTime(session.getStartTimestamp(), session.getTimeout()));
mongoTemplate.insert(bean);
}
......
}ShiroSessionDAO.java
public class ShiroSessionDAO extends AbstractSessionDAO {
private static final Logger log = LoggerFactory.getLogger(ShiroSessionDAO.class);
private ShiroSessionRepository shiroSessionRepository;
public ShiroSessionRepository getShiroSessionRepository() { return shiroSessionRepository;
}
public void setShiroSessionRepository(ShiroSessionRepository shiroSessionRepository) { this.shiroSessionRepository = shiroSessionRepository;
} @Override
public void update(Session session) throws UnknownSessionException {
getShiroSessionRepository().updateSession(session);
} @Override
public void delete(Session session) { if (session == null) {
log.error("session can not be null,delete failed"); return;
}
Serializable id = session.getId(); if (id != null) {
getShiroSessionRepository().deleteSession(id);
}
} @Override
public Collection getActiveSessions() { return getShiroSessionRepository().getAllSessions();
} @Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId);
getShiroSessionRepository().saveSession(session); return sessionId;
} @Override
protected Session doReadSession(Serializable sessionId) { return getShiroSessionRepository().getSession(sessionId);
}
} OK!所有基础类已经完成,最后写一个config用来全部初始化和配置Shiro
@Configurationpublic class ShiroConfig { @Resource
private MongoTemplate mongoTemplate; @Resource
private SystemUserService systemUserService;// 这是用来判断用户名和密码的service
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403"); // 拦截器.
Map filterChainDefinitionMap = new linkedHashMap();
filterChainDefinitionMap.put("/static
@Bean
public ShiroDbRealm myShiroRealm() {
ShiroDbRealm myShiroRealm = new ShiroDbRealm(systemUserService); return myShiroRealm;
} @Bean
public DefaultWebSessionManager sessionManager(ShiroSessionDAO shiroSessionDao) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(1800000l);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionDAO(shiroSessionDao);
sessionManager.setSessionIdcookieEnabled(true);
Simplecookie cookie = new Simplecookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
cookie.setHttponly(true);
cookie.setMaxAge(1800000);
sessionManager.setSessionIdcookie(cookie); return sessionManager;
} @Bean
public ShiroSessionDAO shiroSessionDao(MongoDBSessionRepository shiroSessionRepository) {
ShiroSessionDAO dao = new ShiroSessionDAO();
dao.setShiroSessionRepository(shiroSessionRepository); return dao;
} @Bean
MongoDBSessionRepository shiroSessionRepository() {
MongoDBSessionRepository resp = new MongoDBSessionRepository(mongoTemplate); return resp;
}
} 好了,大功告成,这里只是一个简单的配置,代码也是我从项目里面节选和修改过的,至于在controller里面怎么使用,怎么做不同权限的鉴权工作那就在自己的代码里面实现就行。
文章来源:
http://www.tianshangkun.com/2017/11/10/SpringBoot%E9%9B%86%E6%88%90Shiro%E5%B9%B6%E7%94%A8MongoDB%E5%81%9ASession%E5%AD%98%E5%82%A8/
作者:小红牛
链接:https://www.jianshu.com/p/813a1f6733ed



