spring shiro Permission Control realm Practical Tutorial

  • 2021-11-29 07:15:54
  • OfStack

Directory spring-shiro Privilege Control realm User and Role Entity Realm Class Shiro Configuration Class Controller Serviceshiro Privilege Not Effective Cause Analysis shiro Pit Problem Cause: Privilege Label Definition Problem

spring-shiro Permission Control realm

User and Role Entities

Role.java


@Data
@Entity
public class Role {
    @Id
    @GeneratedValue
    private Integer id;
    private Long userId;
    private String role;
}

User.java


@Data
@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String username;
    private String password;
}

Class Realm

First, build Realm class, inherit from AuthorizingRealm, customize our own authorization and authentication methods. Realm is a component that can access application-specific security data, such as users, roles, and permissions.

Realm.java


public class Realm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    // Authorization 
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // Get the user name from the credentials 
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        // Query user objects by user name 
        User user = userService.getUserByUserName(username);
        // Query the roles owned by users 
        List<Role> list = roleService.findByUserId(user.getId());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        for (Role role : list) {
            // Assign user roles 
            info.addStringPermission(role.getRole());
        }
        return info;
    }
    // Certification 
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // Get the user name of the current user 
        String username = (String) authenticationToken.getPrincipal();
        // Find users from the database by user name 
        User user = userService.getUserByUserName(username);
        if (userService.getUserByUserName(username) == null) {
            throw new UnknownAccountException(
                    " No corresponding user information was found in this system. ");
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName());
        return info;
    }
}

Shiro Configuration Class

ShiroConfig.java


@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // The following is the filter chain, which filters in sequence, so /** Need to put it last 
        // Open static resources 
        filterChainDefinitionMap.put("/favicon.ico", "anon");// Website icon 
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(myRealm());
        return defaultWebSecurityManager;
    }
    @Bean
    public MyRealm myRealm() {
        MyRealm myRealm = new MyRealm();
        return myRealm;
    }
}

Controller

UserController.java


@Controller
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/")
    public String index() {
        return "index";
    }
    @GetMapping("/login")
    public String toLogin() {
        return "login";
    }
    @GetMapping("/admin")
    public String admin() {
        return "admin";
    }
    @PostMapping("/login")
    public String doLogin(String username, String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "redirect:admin";
    }
    @GetMapping("/home")
    public String home() {
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.checkPermission("admin");
        } catch (UnauthorizedException exception) {
            System.out.println(" Insufficient permissions ");
        }
        return "home";
    }
    @GetMapping("/logout")
    public String logout() {
        return "index";
    }
}

Service

UserService.java


@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    public User getUserByUserName(String username) {
        return userDao.findByUsername(username);
    }
    @RequiresRoles("admin")
    public void send() {
        System.out.println(" I have a role now admin You can execute this statement ");
    }
}

Cause analysis of shiro authority not taking effect

Pits encountered by shiro

-The project uses shiro to do login checksum authority management, encountered small pit when configuring authority, record 1.

Environment: springboot+freemarker+shiro Scenario: Background management, menu configuration and button permissions are divided into three levels. Level 12 only considers whether to view permissions for the time being, and level 3 is page button permissions, which are added, deleted and changed. See the picture for details Problem: Level 12 is normal, and Level 3 authority does not work!

Permission labels are defined as follows:

标签定义 页面1 页面2
第1层级 one:view two:view
第2层级 one:page1:view two:page2:view
第3层级 one:page1:view:add two:page2:view:add

At first, I suspected that the database was not entered. After viewing, the permission label corresponds to the role and is excluded.

After the suspicion is a page problem, the third level label and the 12th level with the same page, still does not work, excluded.

Later, it was suspected that the definition of permission label was a problem, so the Level 3 label was changed to one: page 1: data: add, and a miracle appeared and the permission took effect. Verify that there is a problem with the definition of permission labels.

Problem cause: Permission label definition problem

But then I think about why this kind of problem occurs. Each label is unique. I am interested in the verification of permission labels in shiro. Look at the source code. After 1-way debug, I finally saw the key in org. apache. shiro. authz. permission. The core code is as follows


// When this method returns true This permission is indicated when 
// This p Represents the permission label to which the current loop matches 
public boolean implies(Permission p) {
// By default only supports comparisons with other WildcardPermissions
if (!(p instanceof WildcardPermission)) {
return false;
}
    WildcardPermission wp = (WildcardPermission) p;
 // Divide the current label into 1 A set Collection such as one:page1:view:add  Will be divided into [[one], [page1], [view], [add]] ) 
    List<Set<String>> otherParts = wp.getParts();
    int i = 0;
 // Loop matching permission label 
    for (Set<String> otherPart : otherParts) {
        // If this permission has less parts than the other permission, everything after the number of parts contained
        // in this permission is automatically implied, so return true
  // When all loops match, they do not return false, Returns the true, This getparts() The method is to get the permission label of the current loop of the current role ( [[one], [page1], [view]] ) 
        if (getParts().size() - 1 < i) {
            return true;
        } else {
            Set<String> part = getParts().get(i);
   /* If it contains' *' And the label that does not contain the current split returns false,
    * When the user can view the page, that is, the current role has one:page1:view Label 
    * Here " !part.contains(WILDCARD_TOKEN) "Return true, No. 1 2 A " part.containsAll(otherPart) " one Will match the current label ** Match one,
    * That is to say, all the loops here return are false, So it didn't happen in the end true, So I returned on it 1 A true . 
            if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {
                return false;
            }
            i++;
        }
    }

Summary 1: Through analysis, we can see that when shiro defines permission labels, it is necessary to consider matching problems instead of inclusion problems. Similar to aaa and aaab, the following labels will be invalid.


Related articles: