SpringSecurity之授权


SpringSecurity之授权

目录
  • SpringSecurity之授权
    • 1. 写在前面的话
    • 2. web授权
      • 1. 建库
      • 2. 添加查询权限的接口
      • 3. 前端页面的编写
      • 4. SpringSecurity配置
      • 5. Controller配置
    • 3. 结语

1. 写在前面的话

此文并非教程, 而是个人学习SpringSecurity时的记录以及一些踩坑解决

如果能帮到大家, 那就让人非常开心了

另外, SpringSecurity的授权分为web授权和方法授权, 本文只说明了web授权, 方法授权实际上就是SpringSecurity控制对方法和接口的访问, 需要学习的小伙伴可以自行学习, 笔者在今后的工作中如果用到的话也会回来添加相关内容

好了, 让我们看看笔者的一些学习心得吧

2. web授权

个人认为授权较之认证简单了许多, 大概是本人在认证把该踩的坑都踩了一遍吧...

首先, 我们需要建立数据库

1. 建库

我们需要以下的几张表

image-20201124100602850

  • 角色表

    image-20201124100621949

  • 权限表

    image-20201124100632156

  • 用户表(这个在认证中已经建立了)

  • 角色权限关联表 (此处为管理员有1和2两个权限)

    image-20201124100719214

  • 用户角色关联表

    image-20201124100823160

    • 关联表是为了方便拓展, 正常的业务都是这样的, 存在一对多和多对多的关系

2. 添加查询权限的接口

权限的信息也是存放在UserDetails中的, 因此我们也要实现通过用户id查询用户对应权限的功能

  • 建立对应的实体类(此处省略)

    image-20201124101044063

  • 添加接口以及其实现类

    • dao

      //根据用户id查询用户权限
      List getPermissionByUserId(String userId);
      
    • service接口

      List getPermissionByUserId(String userId);
      
    • 接口实现类

      @Override
      public List getPermissionByUserId(String userId) {
          return userMapper.getPermissionByUserId(userId);
      }
      
  • 在xml中添加查询的sql

    
    
    
    • 注意, 这里我们使用了子查询, 同时, 由于会查出多条结果, 我们要酌情考虑是否要使用 in 语句, 将多个结果放在select语句的条件中

3. 前端页面的编写

我们使用的是 layui的默认后端模板

  • 模板的定义

    先编写一个后台模板文件

    
    
    
        
        
        layout 后台大布局 - Layui
        
    
    
    
    
    
    
    
    
    
    
    
    • 注意
      • 我们为了获得SpringSecurity中的用户名, 使用了SpringSecurity的thymeleaf方言, 可以实现细粒度的控制(依据权限是否显示某些标签)
      • 引入命名空间, 这样就有代码提示了(不引入其实也无所谓~) xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
  • 测试用页面

    为了测试权限, 我们定义了三个按钮, 分别对应三个权限(我们在下一节的SpringSecurity配置类中可以看到)

    
    
    
        
        页面
    
    
    
    
    成功应用模板!

4. SpringSecurity配置

//授权
http
        .authorizeRequests()
        .antMatchers("/r/r1").hasAnyAuthority("p1")
        .antMatchers("/r/r2").hasAnyAuthority("p2")
        .antMatchers("/r/r3").access("hasAuthority('p1') and hasAuthority('p2')")
        .antMatchers("/r/**").authenticated().anyRequest().permitAll();

在配置类中配置授权的规则

注意

  • Authority和Role都是角色管理, 区别是Role会加一个 ROLE_ 前缀, 具体的区别可以在网上自行查看, 一般来说, 我们使用Authority就行了

5. Controller配置

  • RestController处理AJAX
package com.wang.spring_security_framework.controller;

import com.alibaba.fastjson.JSON;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class RestfulJumpController {
    @RequestMapping("/toR1")
    public String toR1Page() {
        String url = "/r/r1";
        String code = "204";
        String msg = "即将跳转!";
        Map resultMap = new HashMap<>();
        resultMap.put("url", url);
        resultMap.put("code", code);
        resultMap.put("msg", msg);
        return JSON.toJSONString(resultMap);
    }

    @RequestMapping("/toR2")
    public String toR2Page() {
        String url = "/r/r2";
        String code = "204";
        String msg = "即将跳转!";
        Map resultMap = new HashMap<>();
        resultMap.put("url", url);
        resultMap.put("code", code);
        resultMap.put("msg", msg);
        return JSON.toJSONString(resultMap);
    }

    @RequestMapping("/toR3")
    public String toR3Page() {
        String url = "/r/r3";
        String code = "204";
        String msg = "即将跳转!";
        Map resultMap = new HashMap<>();
        resultMap.put("url", url);
        resultMap.put("code", code);
        resultMap.put("msg", msg);
        return JSON.toJSONString(resultMap);
    }

}

我们用RestController处理了Ajax的跳转请求, 并返回了JSON信息, 让前端进行url跳转

  • 测试的授权Controller

这里的Controller用于显示对应的资源目录下的一些内容, 其中我们从会话中获取了当前登录的用户名

package com.wang.spring_security_framework.controller;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/r")
public class AuthorizeTestController {

    //从会话中获取当前登录用户名
    private String getUserName(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //未登录, 返回null
        if(!authentication.isAuthenticated()) {
            return null;
        }
        Object principal = authentication.getPrincipal();
        String username;
        if (principal instanceof UserDetails) {
            username = ((UserDetails) principal).getUsername();
        } else {
            username = principal.toString();
        }
        return username;
    }

    @RequestMapping("/r1")
    public String R1() {
        return getUserName() + "访问资源1";
    }

    @RequestMapping("/r2")
    public String R2() {
        return getUserName() + "访问资源2";
    }

    @RequestMapping("/r3")
    public String R3() {
        return getUserName() + "访问资源3";
    }
}

3. 结语

本篇看起来很简单, 事实上也确实很简单......

主要需要理解的是数据库的建立以及关联表的处理, 其中的SQL语句才是最难搞的

访问没有授权的页面, 会爆出 405 错误, 我们可以自定义错误页面来处理这种错误(此处就不叙述了, 属于SpringBoot的内容~)

欢迎小伙伴批评与交流~