spring shiro Permission Control realm Practical Tutorial
- 2021-11-29 07:15:54
- OfStack
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.