Goodbye Shiro!

1 Introduction

As a background developer, the term permission should be considered very familiar. Even classes in java have "permissions" such as public and private. Shiro has been used as the framework for rights management in previous projects. To be honest, shiro is indeed quite powerful, but it also has many disadvantages. Shiro's default login address is still login.jsp, and many categories need to be rewritten when using shiro in the front-end and back-end separation mode; storing user information on the mobile phone, maintaining login status, etc., is also a problem for shiro.

In distributed projects, such as e-commerce projects, there is actually no need for clear authority division. To put it bluntly, I think there is no need to do too much troublesome authority management, and everything is kept simple. What's more, shiro is simply a "disaster" for various distributed frameworks such as springCloud. Every subsystem has to write something about Shiro, and slowly, it becomes more and more disgusting. The zuul gateway is here to show its talents, controlling the user's login, authenticating the user's authority, and so on. The zuul gateway controls user login, which will be explained in detail after authentication. The above is my humble opinion.

Then recently I discovered jcasbin, another permission framework. Although there are not many blogs on the Internet, I can use it after reading it for a while.

github address: https://github.com/casbin/jcasbin

2. Prepare

I won’t introduce the basics of Spring Boot. It is recommended to watch this practical project:

https://github.com/javastacks/spring-boot-best-practice

1. Introduction of mavan warehouse

<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>

2. Configuration file

jcasbin puts the user's role and permission information (access path) in the configuration file, and then reads the configuration file through the input stream. There are two main configuration files: model.conf and policy.csv. The simple use of GitHub has been mentioned, so I won’t go into details here.

In fact, you can also read the role permission configuration of the database. So we can extract the information about the database and set it dynamically.

@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 + ];
  }

}

In this way, we can configure related configurations in application.properties. model.conf is a fixed file, just copy it and place it in the newly created folder at the same level as src. The content of policy.csv can be read from the database.

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

3. Read permission information for initialization

We need to initialize the Enforcer class and load the information in the configuration file. So we write a class to implement InitializingBean, and initialize this class when the container is loaded for subsequent use.

@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;
  }

}

In this class, we inject the written configuration class, then convert it to static, instantiate the Enforcer in the afterPropertiesSet method and load the policy (strategy, role permission/url correspondence).

At the same time, two methods are written to add and delete policies. Policy is a custom class that encapsulates the official collection/array.

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 + ];
  }

}

4. use

1. Authority control

The permission control of jcasbin is very simple. You can customize a filter and if judgment can be done. Yes, it’s that simple.

@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() {

  }

}

Mainly use the enforcer.enforce(user, path, method) method to match users, access resources, and methods. The logic here can be implemented according to your own business. Before this filter, you can also add a filter to determine whether the user is logged in.

2. Add and delete permissions

For permission operations, just call the corresponding method in the EnforcerFactory written above. Moreover, the effect of synchronization can be achieved. That is, without restarting the server or any other operations, after adding or deleting user permissions, the corresponding access of the user will be affected.

@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();
  }

5. Finally

In fact, jcasbin can be combined with SpringCloud's zuul to realize unified login and authority control of users. You can customize a filter to inherit ZuulFilter, and there is basically no difference in other places. I will write about this later.

Copyright statement: This article is an original article of CSDN blogger "Red Lotus Root Fragrance, Residual Jade and Autumn", and follows the CC 4.0 BY-SA copyright agreement. For reprinting, please attach the original source link and this statement. Original link: https://blog.csdn.net/WayneLee0809/article/details/85702551

Recent hot article recommendation:

1. 1,000+ Java interview questions and answers (2022 latest version)

2. Brilliant! Java coroutines are coming. . .

3. Spring Boot 2.x tutorial, too comprehensive!

4. Don't fill the screen with explosions and explosions, try the decorator mode, this is the elegant way! !

5. The latest release of "Java Development Manual (Songshan Edition)", download quickly!

Feel good, don't forget to like + forward!

Guess you like

Origin blog.csdn.net/youanyyou/article/details/132602903