Spring Boot集成Shiro并利用MongoDB做Session存储的方法详解
前言
shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/ 它提供了很方便的权限认证和登录的功能.
而springboot作为一个开源框架,必然提供了和shiro整合的功能!
之前项目鉴权一直使用的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版本是
<shiro.version>1.2.3</shiro.version>
添加依赖:
<dependency> <groupid>org.apache.shiro</groupid> <artifactid>shiro-core</artifactid> <version>${shiro.version}</version> </dependency> <dependency> <groupid>org.apache.shiro</groupid> <artifactid>shiro-web</artifactid> <version>${shiro.version}</version> </dependency> <dependency> <groupid>org.apache.shiro</groupid> <artifactid>shiro-spring</artifactid> <version>${shiro.version}</version> </dependency> <dependency> <groupid>org.mongodb</groupid> <artifactid>mongo-java-driver</artifactid> <version>3.0.0</version> </dependency> <dependency> <groupid>org.springframework.data</groupid> <artifactid>spring-data-mongodb</artifactid> <version>1.7.0.release</version> </dependency>
然后在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 { /** * * @param session */ 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; /** * * @return */ public shirosessionrepository getshirosessionrepository() { return shirosessionrepository; } /** * * @param 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<session> 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
@configuration public 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<string, string> filterchaindefinitionmap = new linkedhashmap<string, string>(); filterchaindefinitionmap.put("/static/**", "anon"); filterchaindefinitionmap.put("/ajaxlogin", "anon"); filterchaindefinitionmap.put("/libs/**", "anon"); filterchaindefinitionmap.put("/images/**", "anon"); filterchaindefinitionmap.put("/logout", "logout"); filterchaindefinitionmap.put("/**", "authc"); shirofilterfactorybean.setfilterchaindefinitionmap(filterchaindefinitionmap); return shirofilterfactorybean; } public authorizationattributesourceadvisor authorizationattributesourceadvisor( defaultwebsecuritymanager securitymanager) { authorizationattributesourceadvisor adv = new authorizationattributesourceadvisor(); adv.setsecuritymanager(securitymanager); return adv; } @bean public defaultwebsecuritymanager securitymanager(defaultwebsessionmanager sessionmanager, shirodbrealm myshirorealm) { defaultwebsecuritymanager securitymanager = new defaultwebsecuritymanager(); // 设置realm. securitymanager.setrealm(myshirorealm); securitymanager.setsessionmanager(sessionmanager); return securitymanager; } /** * 身份认证realm; (这里传递systemuserservice给自定义的shirodbrealm初始化) * * @return */ @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里面怎么使用,怎么做不同权限的鉴权工作那就在自己的代码里面实现就行。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
下一篇: java多线程编程之为什么要进行数据同步