好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

spring-shiro权限控制realm实战教程

spring-shiro权限控制realm

用户与角色实体

Role.java

?

1

2

3

4

5

6

7

8

9

@Data

@Entity

public class Role {

     @Id

     @GeneratedValue

     private Integer id;

     private Long userId;

     private String role;

}

User.java

?

1

2

3

4

5

6

7

8

9

@Data

@Entity

public class User {

     @Id

     @GeneratedValue

     private Long id;

     private String username;

     private String password;

}

Realm类

首先建立 Realm 类,继承自 AuthorizingRealm,自定义我们自己的授权和认证的方法。Realm 是可以访问特定于应用程序的安全性数据(如用户,角色和权限)的组件。

Realm.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

public class Realm extends AuthorizingRealm {

     @Autowired

     private UserService userService;

     //授权

     @Override

     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

         //从凭证中获得用户名

         String username = (String) SecurityUtils.getSubject().getPrincipal();

         //根据用户名查询用户对象

         User user = userService.getUserByUserName(username);

         //查询用户拥有的角色

         List<Role> list = roleService.findByUserId(user.getId());

         SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

         for (Role role : list) {

             //赋予用户角色

             info.addStringPermission(role.getRole());

         }

         return info;

     }

     //认证

     @Override

     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

         //获得当前用户的用户名

         String username = (String) authenticationToken.getPrincipal();

         //从数据库中根据用户名查找用户

         User user = userService.getUserByUserName(username);

         if (userService.getUserByUserName(username) == null ) {

             throw new UnknownAccountException(

                     "没有在本系统中找到对应的用户信息。" );

         }

         SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName());

         return info;

     }

}

Shiro 配置类

ShiroConfig.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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

         //以下是过滤链,按顺序过滤,所以/**需要放最后

         //开放的静态资源

         filterChainDefinitionMap.put( "/favicon.ico" , "anon" ); //网站图标

         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;

     }

}

控制器

UserController.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

@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( "没有足够的权限" );

         }

         return "home" ;

     }

     @GetMapping ( "/logout" )

     public String logout() {

         return "index" ;

     }

}

Service

UserService.java

?

1

2

3

4

5

6

7

8

9

10

11

12

@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( "我现在拥有角色admin,可以执行本条语句" );

     }

}

shiro权限不生效原因分析

shiro遇到的坑

-项目中使用shiro做登录校验和权限管理,在配置权限时遇到小坑,记录一下。

环境:springboot+freemarker+shiro 场景:后台管理,配置菜单以及按钮权限,分为三个层级,一二级暂时只考虑是否查看权限,第三层级为页面按钮权限,分增删改查。详情看图 问题:一二层级正常,第三层级权限不起作用!

权限标签定义如下:

标签定义 页面一 页面二
第一层级 one:view two:view
第二层级 one:page1:view two:page2:view
第三层级 one:page1:view:add two:page2:view:add

开始怀疑是数据库没有录入,查看后权限标签与角色已对应,排除。

后面怀疑是页面问题,后面把第三层级标签与第一二层级同一页面,依然不起作用,排除。

后面怀疑是权限标签定义问题,把第三层级标签改为one:page1:data:add,奇迹出现,权限生效。证实权限标签定义出了问题。

问题原因:权限标签定义问题

但是后来想想为什么会出现这种问题,每个标签都是独一无二的,对此我对shiro对于权限标签的校验产生了兴趣,查看源码,一路debug后最终在org.apache.shiro.authz.permission中看到了关键所在,核心代码如下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

//当这个方法返回true时说明有此权限

//这个p是代表当前循环匹配到的权限标签

public boolean implies(Permission p) {

// By default only supports comparisons with other WildcardPermissions

if (!(p instanceof WildcardPermission)) {

return false ;

}

     WildcardPermission wp = (WildcardPermission) p;

  //把当前标签转分割成一个set集合(如one:page1:view:add 会分割成[[one], [page1], [view], [add]])

     List<Set<String>> otherParts = wp.getParts();

     int i = 0 ;

  //循环匹配权限标签

     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

   //当全部循环匹配完没有返回false,则返回true,这个getparts()方法是获取当前角色当前循环的权限标签([[one], [page1], [view]])

         if (getParts().size() - 1 < i) {

             return true ;

         } else {

             Set<String> part = getParts().get(i);

    /*如果包含有‘*'而且不包含当前分割后的标签则返回 false ,

     *当用户可以查看页面,也就是说当前角色拥有one:page1:view标签

     *这里【!part.contains(WILDCARD_TOKEN)】返回 true ,第二个【part.containsAll(otherPart)】one会跟当前标签匹**配one,

     *也就是说这里全部循环完返回的都是 false ,所以最后都没 true ,于是在上面返回了一个 true 。

             if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {

                 return false ;

             }

             i++;

         }

     }

小结一下:通过分析,我们看到了shiro在定义权限标签时,要主意匹配问题,不要存在包含问题,类似aaa 和aaab ,会导致后面标签失效。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://zhengkai.blog.csdn.net/article/details/80153421

查看更多关于spring-shiro权限控制realm实战教程的详细内容...

  阅读:20次