再见了 shiro!!!(荣耀典藏版)
?
目录
前言
大家好,我是月夜枫,作为一名合格的后台开发人员,权限这个名词应该算是特别熟悉的了。就算是java里的类也有 public、private 等“权限”之分。之前项目里一直使用shiro作为权限管理的框架。说实话,shiro的确挺强大的,但是它也有很多不好的地方。shiro默认的登录地址还是login.jsp,前后端分离模式使用shiro还要重写好多类;手机端存储用户信息、保持登录状态等等,对shiro来说也是一个难题。
在分布式项目里,比如电商项目,其实不太需要明确的权限划分,说白了,我认为没必要做太麻烦的权限管理,一切从简。何况shiro对于springCloud等各种分布式框架来说,简直就是“灾难”。每个子系统里都要写点shiro的东西,慢慢的,越来越恶心。zuul网关就在这里大显身手了,控制用户的登录,鉴定用户的权限等等。zuul网关控制用户登录,鉴权以后再详说。以上拙见。
然后最近我发现了另一个权限框架jcasbin,虽然网上还没有很多关于博客,但是我看了一会就可以使用了。
github地址:https://github.com/casbin/jcasbin
一、基础知识
基于springboot1.5.10,但是和springboot关系不太大。
1、mavan仓库引入
<dependency>
????<groupId>org.casbin</groupId>
????<artifactId>jcasbin</artifactId>
????<version>1.1.0</version>
</dependency>
<dependency>
????<groupId>org.casbin</groupId>
????<artifactId>jdbc-adapter</artifactId>
????<version>1.1.0</version>
</dependency>
二、配置文件
jcasbin把用户的角色、权限信息(访问路径)放置在配置文件里,然后通过输入流读取配置文件。主要有两个配置文件:model.conf 和 policy.csv。简单的使用GitHub里都讲了,在此就不再赘述了。
其实也可以读取数据库的角色权限配置。所以我们可以把关于数据库的信息提取出来,可以进行动态设置。
@Configuration
@ConfigurationProperties(prefix =?org.jcasbin)
public?class?EnforcerConfigProperties {
?
??private?String?url;
??
??private?String?driverClassName;
??
??private?String?username;
??
??private?String?password;
??
??private?String?modelPath;
?
??public?String?getUrl() {
????return?url;
??}
?
??public?void?setUrl(String?url) {
????this.url = url;
??}
?
??public?String?getDriverClassName() {
????return?driverClassName;
??}
?
??public?void?setDriverClassName(String?driverClassName) {
????this.driverClassName = driverClassName;
??}
?
??public?String?getUsername() {
????return?username;
??}
?
??public?void?setUsername(String?username) {
????this.username = username;
??}
?
??public?String?getPassword() {
????return?password;
??}
?
??public?void?setPassword(String?password) {
????this.password = password;
??}
?
??public?String?getModelPath() {
????return?modelPath;
??}
?
??public?void?setModelPath(String?modelPath) {
????this.modelPath = modelPath;
??}
?
??@Override
??public?String?toString() {
????return?EnforcerConfigProperties [url=?+ url +?, driverClassName=?+ driverClassName +?, username=
????????+ username +?, password=?+ password +?, modelPath=?+ modelPath +?];
??}
??
}
这样我们就可以在application.properties里进行相关配置了。model.conf是固定的文件,之间复制过来放在新建的和src同级的文件夹下即可。policy.csv的内容是可以从数据库读取的。
org.jcasbin.url=jdbc:mysql://localhost:3306/casbin?useSSL=false
org.jcasbin.driver-class-name=com.mysql.jdbc.Driver
org.jcasbin.username=root
org.jcasbin.password=root
org.jcasbin.model-path=conf/authz_model.conf
三、权限信息初始化
我们要对Enforcer这个类初始化,加载配置文件里的信息。所以我们写一个类实现InitializingBean,在容器加载的时候就初始化这个类,方便后续的使用。
@Component
public?class?EnforcerFactory?implements?InitializingBean?{
?
??private?static?Enforcer enforcer;
?
??@Autowired
??private?EnforcerConfigProperties enforcerConfigProperties;
??private?static?EnforcerConfigProperties config;
??
??@Override
??public?void?afterPropertiesSet()?throws?Exception?{
????config = enforcerConfigProperties;
????//从数据库读取策略
????JDBCAdapter jdbcAdapter =?new?JDBCAdapter(config.getDriverClassName(),config.getUrl(),config.getUsername(),
??????????????????????????config.getPassword(),?true);
????enforcer =?new?Enforcer(config.getModelPath(), jdbcAdapter);
????enforcer.loadPolicy();//Load the policy from DB.
??}
??
??/**
???* 添加权限
???*?@param?policy
???*?@return
???*/
??public?static?boolean?addPolicy(Policy policy){
????boolean?addPolicy = enforcer.addPolicy(policy.getSub(),policy.getObj(),policy.getAct());
????enforcer.savePolicy();
????
????return?addPolicy;
??}
??
??/**
???* 删除权限
???*?@param?policy
???*?@return
???*/
??public?static?boolean?removePolicy(Policy policy){
????boolean?removePolicy = enforcer.removePolicy(policy.getSub(),policy.getObj(),policy.getAct());
????enforcer.savePolicy();
????
????return?removePolicy;
??}
??
??public?static?Enforcer?getEnforcer(){
????return?enforcer;
??}
??
}
在这个类里,我们注入写好的配置类,然后转为静态的,在afterPropertiesSet方法里实例化Enforcer并加载policy(策略,角色权限/url对应关系)。
同时又写了两个方法,用来添加和删除policy,Policy是自定的一个类,对官方使用的集合/数组进行了封装。
public?class?Policy {
??/**想要访问资源的用户 或者角色*/
??private?String?sub;
??
??/**将要访问的资源,可以使用 * 作为通配符,例如/user/* */
??private?String?obj;
??
??/**用户对资源执行的操作。HTTP方法,GET、POST、PUT、DELETE等,可以使用 * 作为通配符*/
??private?String?act;
?
??public?Policy() {
????super();
??}
??
??/**
???*
???* @param sub 想要访问资源的用户 或者角色
???* @param obj 将要访问的资源,可以使用 * 作为通配符,例如/user/*
???* @param act 用户对资源执行的操作。HTTP方法,GET、POST、PUT、DELETE等,可以使用 * 作为通配符
???*/
??public?Policy(String?sub,?String?obj,?String?act) {
????super();
????this.sub = sub;
????this.obj = obj;
????this.act = act;
??}
?
??public?String?getSub() {
????return?sub;
??}
?
??public?void?setSub(String?sub) {
????this.sub = sub;
??}
?
??public?String?getObj() {
????return?obj;
??}
?
??public?void?setObj(String?obj) {
????this.obj = obj;
??}
?
??public?String?getAct() {
????return?act;
??}
?
??public?void?setAct(String?act) {
????this.act = act;
??}
?
??@Override
??public?String?toString() {
????return?Policy [sub=?+ sub +?, obj=?+ obj +?, act=?+ act +?];
??}
??
}
四、如何使用
1、权限控制
jcasbin的权限控制非常简单,自定义一个过滤器,if判断就可以搞定,没错,就这么简单。
@WebFilter(urlPatterns =?/*?, filterName =?JCasbinAuthzFilter)
@Order(Ordered.HIGHEST_PRECEDENCE)//执行顺序,最高级别最先执行,int从小到大
public?class?JCasbinAuthzFilter?implements?Filter?{
??
??private?static?final?Logger log = LoggerFactory.getLogger(JCasbinAuthzFilter.class);
?
??private?static?Enforcer enforcer;
?
??@Override
??public?void?init(FilterConfig filterConfig)?throws?ServletException?{
??}
?
??@Override
??public?void?doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
??????throws?IOException, ServletException?{
????HttpServletRequest request = (HttpServletRequest) servletRequest;
????????HttpServletResponse response = (HttpServletResponse) servletResponse;
????????
????????String user = request.getParameter(username);
????????String path = request.getRequestURI();
????????String method = request.getMethod();
?
????????enforcer = EnforcerFactory.getEnforcer();
????????if?(path.contains(anon)) {
??????????chain.doFilter(request, response);
????}else?if?(enforcer.enforce(user, path, method)) {
??????chain.doFilter(request, response);
????}?else?{
??????log.info(无权访问);
??????Map<String, Object> result =?new?HashMap<String, Object>();
????????????result.put(code,?1001);
????????????result.put(msg,?用户无权访问);
????????????result.put(data,null);
????????????response.setCharacterEncoding(UTF-8);
????????????response.setContentType(application/json);
????????????response.getWriter().write(JSONObject.toJSONString(result,SerializerFeature.WriteMapNullValue));
??????}
????
??}
?
??@Override
??public?void?destroy()?{
????
??}
?
}
主要是用enforcer.enforce(user, path, method)这个方法对用户、访问资源、方式进行匹配。这里的逻辑可以根据自己的业务来实现。在这个过滤器之前还可以添加一个判断用户是否登录的过滤器。
2、添加删除权限
对于权限的操作,直接调用上面写好的EnforcerFactory里对应的方法即可。并且,可以达到同步的效果。就是不用重启服务器或者其他任何操作,添加或删除用户权限后,用户对应的访问就会收到影响。
@PutMapping(/anon/role/per)
??public?ResultBO<Object> addPer(){
????
????EnforcerFactory.addPolicy(new?Policy(alice,?/user/list,?*));
????
????return?ResultTool.success();
??}
??
??@DeleteMapping(/anon/role/per)
??public?ResultBO<Object> deletePer(){
????
????EnforcerFactory.removePolicy(new?Policy(alice,?/user/list,?*));
????
????return?ResultTool.success();
??}
五、总结
其实可以把jcasbin和SpringCloud的zuul结合来实现用户的统一登录和权限控制。自定义一个过滤器继承ZuulFilter即可,其他地方基本没啥区别。这个以后再写。
?
好了,本文的技术部分就到这里啦。
最后说一句(求关注,别白嫖我)
如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下,您的支持是我坚持写作最大的动力。
求一键三连:点赞、转发、在看。
我从清晨走过,也拥抱夜晚的星辰,人生没有捷径,你我皆平凡,你好,陌生人,一起共勉。
?
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!