一.目标
1.外部请求统一从网关zuul进入,而且服务内部互相调用接口要校验权限html
2.cloud和shiro结合,达到单点登陆,和集中一个服务完成权限管理,其余业务服务不须要关注权限如何实现mysql
3.其余服务依然能够控制权限细粒度到接口,如在接口上使用@RequirePermisson等注解,方便开发redis
二.思路
SpirngCloud zuul网关有两个做用,一个是分配路由,一个是过滤。sql
zuul的过滤器做用有限,只能简单的作一些某个url是否可以访问之类的,没法像shiro同样细粒度到某个用户是否有某种权限;数据库
shiro单体应用你们都会作,那变成微服务后,难道每一个服务都要写一套shiro框架?这显然也太麻烦。后端
1.在zuul服务里用shiro,作成动态url权限控制,就是把访问哪一个url须要用什么权限,写入数据库,在过滤器读取与用户有的权限做对比;可是服务互相调用校验就行不通了,由于服务间调用不走zuul浏览器
2.写一个服务专用于shiro认证和受权,包含用户、权限的curd,暴露出查询一个用户拥有什么权限的接口;在其余服务中,都写一个拦截器拿访问者token去受权服务拿此用户的权限,再跟请求的url对比;或者能够自定义注解用aop,注解标注的是访问此url须要什么权限,远程调用受权服务接口查询当前用户全部权限,与请求的url对比。缓存
可是这个要本身实现拦截器。安全
3.第二种思路的简单版本。服务器
写一个server服务专用于shiro认证和受权,包含用户、权限的curd,暴露出查询一个用户拥有什么权限的接口;
在写一个client项目打成jar包供其余服务使用,也是用shiro框架,不一样于server服务的是,在realm中只有受权方法,没有认证方法,而且受权方法的实现是去server远程查询权限,再返回给client项目的安全管理器。且client的登陆接口写成server的登陆接口,这样未登陆的用户都会跳转到server登陆,想办法保存下原路径,登陆成功后再返回原服务;同时作成session共享
普通业务服务只须要依赖于client,就至关于每一个服务都有了一套shiro。
这种思路来自于《跟我学shiro》的多项目集中权限,其实想一想这种思路是能够的,shiro本质也是靠拦截器进行权限校验,虽然至关于每一个服务都开启了一套shiro,但也就是容器中多了一些shiro拦截器和实例,并且能够用shiro的各类功能,开发方便。能够完成咱们的三个目标。
三.其余思路
1.分布式session
用户在网关进行登陆认证;若是经过,将用户信息存在第三方组件,mysql、redis;后端其余服务能够经过第三方组件拿到用户数据。
这种方案值得推荐,方便扩展,但依赖于第三方组件,注意第三方组件的高可用。
2.客户端token与网关结合
服务器无session,将用户信息存储在token,好比JWT。
了解JWThttps://www.cnblogs.com/cjsblog/p/9277677.html
客户端携带用jwt加密的token,访问网关,token携带了用户的信息
网关对token认证和校验
校验经过网关后,请求携带token到具体服务,能够校验具体的url权限
若是用户信息量大,则不适合,由于都是存储在客户端的;而且token要在网关注注销
zuul + OATHU2+JWT
3.浏览器cookie和网关结合。
和上述方案相同,区别是用户信息彻底放在cookie,不用token
---------------------------------------------------------
外加一段优秀的对话:
A:大佬有没有想过用单点登陆sso ,把登陆写成一个服务shiro在这个服务里面做用,须要访问别的服务的时候zuul反向代理到sso的服务进行认证登陆,可这样我如今遇到这样的问题,shiro的受权怎么才能被其余的服务知道,而且在页面进行细粒度级别标签控制拦截
B 回复 A: 嗯。不通过。zuul是给外部调用使用的。。
C回复 A: 看文章,服务之间互相访问是不通过zuul的,只有外部请求访问才经过zull
B回复 A: 其实有简单的方法能够实现相似的目标。就是把我的信息放在Redis或者其余nosql库里,同时放入的还有我的的权限信息,包括可访问的资源信息和角色。而后能够用zuul来进行过滤判断。这样写,就很简单了。不须要用到shiro,也能够避免不少问题。
B: 我如今的想法是吧feignServer单独写成服务,而后将接暴露,其余服务调用这个接口,来进行判断权限。可是这样,会不会有网络延迟发生?
B回复 E: 我是返回统一的result的,里面封装了flag标识。。把shiro单独写成服务,有一个好处就是让其余服务不用再集成shiro,只要去访问shiro这个服务就能知道是否有权限了。其余服务若是要判断的话,就去调用接口就行了。
B回复 A: 可行。已经实现了。feignClient服务暴露出2个接口,权限和角色的认证接口就能够了。注意feign的无状态认证。
A回复 B: 大佬,这样可行,但是别的服务须要受权的时候怎么办
C回复 B: 我认为本质上就是这个思路,cloud里面每一个页面上的请求都要通过网关转发一次,那也要有网络延迟了,没办法。适当加上缓存吧,不用每次都去请求server判断权限
-----------------------但愿能够帮助到你么