用户授权

Author Avatar
ciky 09月 02,2024
  • 在其它设备中阅读本文章
  • 点击生成二维码

用户授权


1 RBAC


基于角色的访问控制 (Role-Based Access Control)

  • 按角色进行授权(比如 总经理 可以查询员工工资信息)

基于资源的访问控制 (Resource-Based Access Control)

  • 按资源(或权限)进行授权 (比如用户必须具有 查询工资权限 才可以查询员工工资信息)

2 资源服务授权流程


(1) 配置nginx代理

#前端开发服务
upstream uidevserver{
	server 127.0.0.1:8601 weight=10;
} 
server {
    listen       80;
    server_name  teacher.51xuecheng.cn;
    #charset koi8-r;
    ssi on;
    ssi_silent_errors on;
    #access_log  logs/host.access.log  main;
    #location / {
     #   alias   D:/itcast2022/xc_edu3.0/code_1/dist/;
     #   index  index.html index.htm;
    #}
    location / {
        proxy_pass   http://uidevserver;
    }

    location /api/ {
            proxy_pass http://gatewayserver/;
    } 


}

(2) 资源服务继承SpringSecurity

在需要授权的接口处使用 @PreAuthorize("hasAuthority('权限标识符')")进行控制

用户没有权限访问时抛出异常:org.springframework.security.access.AccessDeniedException: 不允许访问

image20240726000634409.png

(3) 原理

  • 访问接口时,携带令牌访问

image20240726001302437.png

  • 解析令牌,判断有无接口所需的权限

    image20240726001351953.png


3 授权相关的数据模型


image20240726005844474.png

xc_user:用户表,存储了系统用户信息,用户类型包括:学生、老师、管理员等

xc_role:角色表,存储了系统的角色信息,学生、老师、教学管理员、系统管理员等。

xc_user_role:用户角色表,一个用户可拥有多个角色,一个角色可被多个用户所拥有

xc_menu:模块表,记录了菜单及菜单下的权限

xc_permission:角色权限表,一个角色可拥有多个权限,一个权限可被多个角色所拥有

  • 基本查询

    select u.id from xc_user u where u.username = 't1';    #结果为52
    
    select m.code from xc_menu m where m.id in (
        select p.menu_id from xc_permission p where p.role_id in (
            select t.role_id from xc_user_role t where t.user_id = '52'
        )
    );
    

4 授权测试


  • 自定义UserDetailService
@Slf4j
@Component
public class UserServiceImpl implements UserDetailsService {
//实现UserDetailsService加载用户信息

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private XcMenuMapper xcMenuMapper;


    @Override   //传入的参数是AuthParamsDto的json字符串
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        AuthParamsDto authParamsDto = null;
        try{
            //转成AuthParamsDto对象
            authParamsDto = JSON.parseObject(s, AuthParamsDto.class);
        }catch (Exception e){
            log.info("认证请求不符合项目要求:{}",s);
            throw new    RuntimeException("认证请求数据格式不对");
        }

        //获取认证类型
        String authType = authParamsDto.getAuthType();
        //根据认证类型从spring容器中取出指定的bean
        String beanName = authType+"_authservice";
        AuthService bean = applicationContext.getBean(beanName, AuthService.class);
        //调用统一的excute方法
        XcUserExt xcUserExt = bean.execute(authParamsDto);

        //封装xcUSerExt用户信息为userDetails
        UserDetails userDetails = getUserPrincipal(xcUserExt);

        return userDetails;
    }

    /**
     * 查询用户信息
     * @param user
     * @return
     */
    public UserDetails getUserPrincipal(XcUserExt user){
        String password = user.getPassword();
       //新增------------------------------------------------------------------------------
        //权限
        String[] authorities = {"test"};
        //根据用户id查询用户的权限
        List<XcMenu> xcMenus = xcMenuMapper.selectPermissionByUserId(user.getId());

        if(xcMenus.size()>0){
            List<String> permissions= new ArrayList<>();
            xcMenus.forEach(m->{
                //拿到了用户拥有的权限标识符
                permissions.add(m.getCode());
            });
            //将permissions转成数组
            authorities = permissions.toArray(new String[0]);

        }
        //新增------------------------------------------------------------------------------

        //令牌中不存放密码(为了安全)
        user.setPassword(null);
        //将user对象转成json
        String userString = JSON.toJSONString(user);
        UserDetails userDetails = User.withUsername(userString).password(password).authorities(authorities).build();
        return userDetails;
    }
}
  • XcMenuMapper
public interface XcMenuMapper extends BaseMapper<XcMenu> {
    @Select("SELECT	* FROM xc_menu WHERE id IN (SELECT menu_id FROM xc_permission WHERE role_id IN ( SELECT role_id FROM xc_user_role WHERE user_id = #{userId} ))")
    List<XcMenu> selectPermissionByUserId(@Param("userId") String userId);
}

5 细粒度授权


  • 细粒度授权:也叫数据范围授权,不同用户所拥有的操作权限相同,但能够操作的数据范围是不一样

    ​ 例:用户A和用户B都是教学机构,都拥有"我的课程"权限,但两个用户所查询到的数据是不一样的

image20240726182205925.png