zoukankan      html  css  js  c++  java
  • Spring Security(四)

    前三章的需求不赘述了,直接把本文完成的需求列举如下:

    1. 网站分为首页、用户页面、部门1页面、部门2页面、管理员页面和登录页面;
    2. 使用用户名加密码登录,登录错误要报错;
    3. 根据前三章的功能,用户来自三个方面:1)内存用户user、admin;2)使用后门filter的黑客alex;3)以及数据库中的用户5个(详见数据库数据)
    4. 不同的用户拥有不同的权限,不同的权限可以访问不同的网页;
    5. 登录页不需要任何权限;
    6. 用户页面需要USER权限;管理员页面需要ADMIN权限;部门1页面需要USER1或者MANAGER权限;部门2页面需要USER2或者MANAGER权限;
    7. 如果用户没有登录,则访问需要权限的页面时自动跳转登录页面;
    8. 如果用户已经登录,访问无权页面时服务器会返回一个json,告诉用户访问了没有权限的页面

    1.鉴权原理

    前三章已经介绍过,Spring Securtiy的两大功能是验证和鉴权。验证是验明用户的身份,允许用户登录系统。这个验证过程由一系列AuthenticationProvider构成的链来完成。一旦验证成功,用户身份得到确认,它也同时拥有了一些角色,例如ROLE_USER或者ROLE_ADMIN。

    而鉴权则是一系列判断用户是否有权限访问资源的过程。以本文为例,我们使用 数据库中的myauthorization.resource表来存储了资源以及所需的角色。例如/depart2/**资源,需要ROLE_ADMIN,ROLE_MANAGER,ROLE_DEPART2这三个角色中的任意一个。而如果登录的用户拥有其中某个资源,则可以顺利访问,否则将会抛出AccessDeniedException异常,进入异常处理程序。

    下面按照鉴权处理流程来说一遍鉴权所需编写的代码:

    1.当用户未登录时,访问任何需要权限的资源都会转向登录页面,尝试进行登录;

    2.当用户登录成功时,他会获得一系列角色。

    3.用户访问某资源/xxx时,FilterInvocationSecurityMetadataSource这个类的实现类(本文是MySecurityMetadataSource)会调用getAttributes方法来进行资源匹配。它会读取数据库resource表中的所有记录,对/xxx进行匹配。若匹配成功,则将/xxx对应所需的角色组成一个 Collection<ConfigAttribute>返回;匹配不成功则说明/xxx不需要什么额外的访问权限;

    4.流程来到鉴权的决策类AccessDecisionManager的实现类(MyAccessDecisionManager)中,它的decide方法可以决定当前用户是否能够访问资源。decide方法的参数中可以获得当前用户的验证信息、第3步中获得的资源所需角色信息,对这些角色信息进行匹配即可决定鉴权是否通过。当然,你也可以加入自己独特的判断方法,例如只要用户具有ROLE_ADMIN角色就一律放行;

    5.若鉴权成功则用户顺利访问页面,否则在decide方法中抛出AccessDeniedException异常,这个异常会被AccessDeniedHandler的实现类(MyAccessDeniedHandler)处理。它仅仅是生成了一个json对象,转换为字符串返回给客户端了。

    2.代码解释

    1.首先是关于数据库的库表设计问题,本文中依然使用了单表结构,角色这个字段在两个表中是以逗号分隔,然后在程序中分解开来的,如下所示:

    -- ----------------------------
    --  Table structure for `user`
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `name` varchar(32) DEFAULT NULL COMMENT '姓名',
      `address` varchar(64) DEFAULT NULL COMMENT '联系地址',
      `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '账号',
      `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
      `roles` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '角色',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    -- ----------------------------
    --  Records of `user`
    -- ----------------------------
    BEGIN;
    INSERT INTO `user` VALUES ('1', 'Adam', 'beijing', 'adam','$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6', 'ROLE_USER');
    INSERT INTO `user` VALUES ('2', 'SuperMan', 'shanghang', 'super','$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6', 'ROLE_USER,ROLE_ADMIN');
    INSERT INTO `user` VALUES ('3', 'Manager', 'beijing', 'manager','$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6', 'ROLE_USER,ROLE_MANAGER');
    INSERT INTO `user` VALUES ('4', 'User1', 'shanghang', 'user1','$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6', 'ROLE_USER,ROLE_DEPART1');
    INSERT INTO `user` VALUES ('5', 'User2', 'shanghang', 'user2','$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6', 'ROLE_USER,ROLE_DEPART2');
    COMMIT;
    
    -- ----------------------------
    --  Table structure for `resource`
    -- ----------------------------
    DROP TABLE IF EXISTS `resource`;
    CREATE TABLE `resource` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `url` varchar(255) DEFAULT NULL COMMENT '资源',
      `roles` varchar(255) DEFAULT NULL COMMENT '所需角色',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    -- ----------------------------
    --  Records of `resource`
    -- ----------------------------
    BEGIN;
    INSERT INTO `resource` VALUES ('1', '/depart1/**', 'ROLE_ADMIN,ROLE_MANAGER,ROLE_DEPART1');
    INSERT INTO `resource` VALUES ('2', '/depart2/**', 'ROLE_ADMIN,ROLE_MANAGER,ROLE_DEPART2');
    INSERT INTO `resource` VALUES ('3', '/user/**', 'ROLE_ADMIN,ROLE_USER');
    INSERT INTO `resource` VALUES ('4', '/admin/**', 'ROLE_ADMIN');
    COMMIT;

    2.关于FilterInvocationSecurityMetadataSource类(安全元数据源类)如何设置到WebSecurityConfigurerAdapter中的问题,综合网上目前的文章,使用JavaConfig只有一种方法,即使用withObjectPostProcessor方法,代码如下:

    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Autowired
        BackdoorAuthenticationProvider backdoorAuthenticationProvider;
        @Autowired
        MyUserDetailsService myUserDetailsService;
        @Autowired
        MyAccessDecisionManager myAccessDecisionManager;
        @Autowired
        MySecurityMetadataSource mySecurityMetadataSource;
        @Autowired
        MyAccessDeniedHandler myAccessDeniedHandler;
    
    ...省略
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                        @Override
                        public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                            object.setSecurityMetadataSource(mySecurityMetadataSource);
                            object.setAccessDecisionManager(myAccessDecisionManager);
                            return object;
                        }
                    })
       ...省略
    3.鉴权决策类AccessDecisionManager设置到WebSecurityConfigurerAdapter中有两种方法,其一是如上的方法,其二是
    http
                    .authorizeRequests().accessDecisionManager(myAccessDecisionManager)

    4.本文中MyAccessDeniedHandler类只是返回一个json字符串。如果不处理AccessDeniedException异常,则会显示403错误页面。此处返回的字符串可以和前端结合展示更加丰富的页面。


    3.小结

    在网上其他介绍鉴权的文章中,经常提到Spring Security内置了三个基于投票的AccessDecisionManager实现类,它们分别是AffirmativeBased、ConsensusBased和UnanimousBased。然后如何实现一个投票类。但是我觉得直接继承AccessDecisionManager,然后重写decide方法更加简便。

  • 相关阅读:
    MySQL8安装及使用当中的一些注意事项
    设计模式-观察者模式
    在线教育项目-day12【完善后端整合前端】
    在线教育项目-day12【微信扫码登录】
    在线教育项目-day12【OAuth2】
    在线教育项目-day12【完善登陆页面】
    在线教育项目-day12【整合前端登陆注册页面(2)】
    在线教育项目-day12【整合前端登陆注册页面(1)】
    在线教育项目-day12【解析oken信息】
    在线教育项目-day12【注册接口】
  • 原文地址:https://www.cnblogs.com/xc-xinxue/p/12500853.html
Copyright © 2011-2022 走看看