权限控制与安全认证 Spring Security(三)

简介: 权限控制与安全认证 Spring Security(三)

3.3 编写查询权限方法

在认证后进行授权需要根据用户id查询到用户的权限,写法如下:

1、编写用户、角色、权限实体类

// 不要命名为User,避免和Spring Security提供的User混淆
@Data
public class Users {
  private Integer uid;
  private String username;
  private String password;
  private String phone;
}
// 角色
@Data
public class Role {
  private String rid;
  private String roleName;
  private String roleDesc;
}
// 权限
@Data
public class Permission {
  private String pid;
  private String permissionName;
  private String url;
}

2、编写UsersMapper接口

// 根据用户名查询权限
List<Permission> findPermissionByUsername(String username);

3、编写UsersMapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zj.mapper.UsersMapper">
    <select id="findPermissionByUsername" parameterType="string" resultType="com.zj.pojo.Permission">
           select DISTINCT permission.permissionName,permission.pid,permission.url
           from users LEFT JOIN users_role on users.uid = users_role.uid
                      LEFT JOIN role on users_role.rid = role.rid
                      LEFT JOIN role_permission on role.rid =role_permission.rid
                      LEFT JOIN permission on role_permission.pid = permission.pid
           where users.username = #{username}
    </select>
</mapper>

4、测试方法

package com.zj.security;
import com.zj.mapper.UsersMapper;
import com.zj.pojo.Permission;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;
@SpringBootTest
public class UsersMapperTest {
    @Resource
    private UsersMapper usersMapper;
    @Test
    public void testFindPermissionByUsername(){
        List<Permission> permissions = usersMapper.findPermissionByUsername("张三");
        for (Permission permission : permissions) {
            System.out.println(permission);
        }
    }
}
Permission(pid=1, permissionName=查询报表, url=/reportform/find)
Permission(pid=3, permissionName=查询税务, url=/tax/find)
Permission(pid=2, permissionName=查询工资, url=/salary/find)

5、修改MyUserDetailsService中对用户权限的处理。

package com.zj.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zj.mapper.UsersMapper;
import com.zj.pojo.Permission;
import com.zj.pojo.Users;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Service
public class MyUserDetailsService implements UserDetailsService {
  @Resource
  private UsersMapper usersMapper;
  //自定义认正逻辑
  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    //1.构造查询条件
    QueryWrapper<Users> query = new QueryWrapper<Users>();
    query.eq("username", username);
    //2.查询用户
    Users users = new Users();
    Users users1 = users.selectOne(query);
    if (users1 == null) {
      return null;
    }
    //3.查询用户权限
    List<Permission> permissions = usersMapper.findPermissionByUsername(users1.getUsername());
    //4.将自定义权限集合转为security自带的权限集合
    List<GrantedAuthority> authorities = new ArrayList<>();
    for (Permission permission : permissions) {
      /*SimpleGrantedAuthority为GrantedAuthority接口的实现类*/
       authorities.add(new SimpleGrantedAuthority(permission.getUrl()));
    }
    //5.将查询结果封装为UserDetails对象返回
    UserDetails userDetails = User.withUsername(users1.getUsername())
            .password(users1.getPassword()).authorities(authorities).build();
    return userDetails;
  }
}

3.4 配置类设置访问控制

在给用户授权后,我们就可以给系统中的资源设置访问控制,即拥有什么权限才能访问什么资源。

1、编写控制器类,添加控制器方法资源

@RestController
public class MyController {
  @GetMapping("/reportform/find")
  public String findReportForm() {
    return "查询报表";
   }
  @GetMapping("/salary/find")
  public String findSalary() {
    return "查询工资";
   }
  @GetMapping("/staff/find")
  public String findStaff() {
    return "查询员工";
   }
}

2、修改Security配置类

//需要认证的资源
        http.authorizeHttpRequests()
                .antMatchers("/login.html").permitAll()//登录页不需要认证
                .antMatchers("/reportform/find").hasAnyAuthority("/reportform/find")
                .antMatchers("/salary/find").hasAnyAuthority("/salary/find")
                .antMatchers("/staff/find").hasAnyAuthority("/staff/find")
                .anyRequest().authenticated(); //其他请求都需要认证

3、登录并测试

搞定!!!

3.5 自定义访问控制逻辑

如果资源数量很多,一条条配置需要的权限效率较低。我们可以自定义访问控制逻辑,即访问资源时判断用户是否具有名为该资源URL的权限。

1、自定义访问逻辑

package com.zj.service;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Collection;
@Service
public class MyAuthorizationService {
    // 自定义访问控制逻辑,返回值为是否可以访问资源
    public boolean hasPermission(HttpServletRequest request, Authentication authentication){
        //1.获取认证的用户
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        //2.获取登录用户的权限
        Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
        //3.获取请求的url
        String url = request.getRequestURI();
        //4.将url封装为权限对象
        SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(url);
        //5.判断用户权限集合中是否包含请求的url权限对象
        return authorities.contains(simpleGrantedAuthority);
    }
}

2、配置类中使用自定义访问逻辑

// 权限拦截配置
        http.authorizeRequests()
                .antMatchers("/login.html").permitAll() // 表示任何权限都可以访问
                // 任何请求都使用自定义访问控制逻辑
                .anyRequest().access("@myAuthorizationService.hasPermission(request,authentication)");

3.6 @Secured设置访问控制

除了配置类,在SpringSecurity中提供了一些访问控制的注解。这些注解默认都是不可用的,需要开启后使用。

该注解是基于角色的权限控制,要求UserDetails中的权限名必须以ROLE_开头,当然数据库中的权限也是要以ROLE_开头。

1、在启动类开启注解使用

@SpringBootApplication
@MapperScan("com.zj.mapper")
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(SecurityApplication.class, args);
    }
}

2、在控制器方法上添加注解

@Secured("ROLE_reportform")
@GetMapping("/reportform/find")
public String findReportForm() {
  return "查询报表";
}

3.7 @PreAuthorize设置访问控制

该注解可以在方法执行前判断用户是否具有权限

1、在启动类开启注解使用

@SpringBootApplication
@MapperScan("com.zj.mapper")
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(SecurityApplication.class, args);
    }
}

2、在控制器方法上添加注解

@PreAuthorize("hasAnyAuthority('/reportform/find')")
@GetMapping("/reportform/find")
public String findReportForm() {
  return "查询报表";
}

3、取消配置类中对权限的访问配置

//       // 权限拦截配置
//        http.authorizeRequests()
//                .antMatchers("/login.html").permitAll() // 表示任何权限都可以访问
//                // 任何请求都使用自定义访问控制逻辑
//                .anyRequest().access("@myAuthorizationService.hasPermission(request,authentication)");

 

3.8 前端进行访问控制

SpringSecurity可以在一些视图技术中进行控制显示效果。例如Thymeleaf中,只有登录用户拥有某些权限才会展示一些菜单。

1、在pom中引入Spring Security和Thymeleaf的整合依赖(在创建项目选择起步依赖的时候默认就添加上了)

<!--Spring Security整合Thymeleaf-->
<dependency>
  <groupId>org.thymeleaf.extras</groupId>
  <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>

2、在Thymeleaf中使用Security标签,控制前端的显示内容

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
   xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
  <meta charset="UTF-8">
  <title>主页面</title>
</head>
<body>
<h1>主页面</h1>
<ul>
  <li sec:authorize="hasAnyAuthority('/reportform/find')"><a href="/reportform/find">查询报表</a></li>
  <li sec:authorize="hasAnyAuthority('/salary/find')"><a href="/salary/find">查询工资</a></li>
  <li sec:authorize="hasAnyAuthority('/staff/find')"><a href="/staff/find">查询员工</a></li>
</ul>
<a href="/logout">退出登录</a>
</body>
</html>

这样面对不同权限的用户,前端可以显示不同的菜单。

3.9 403处理方案

使用Spring Security时经常会看见403(无权限),这样的页面很不友好,我们可以自定义403异常处理方案:

1、编写权限不足页面noPermission.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>权限不足</title>
</head>
<body>
<h1>您的权限不足,请联系管理员!</h1>
</body>
</html>

2、编写权限不足处理类

public class MyAccessDeniedHandler implements AccessDeniedHandler {
  @Override
  public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
    response.sendRedirect("/noPermission.html");
   }
}

3、在Spring Security配置文件中配置异常处理

//异常处理
http.exceptionHandling().
        accessDeniedHandler(new MyAccessDeniedHandler());


相关实践学习
云安全基础课 - 访问控制概述
课程大纲 课程目标和内容介绍视频时长 访问控制概述视频时长 身份标识和认证技术视频时长 授权机制视频时长 访问控制的常见攻击视频时长
相关文章
|
4天前
|
安全 Java 数据安全/隐私保护
|
8天前
|
安全 Java API
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(上)
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)
28 0
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(上)
|
8天前
|
存储 安全 Java
第10章 Spring Security 的未来趋势与高级话题(2024 最新版)(下)
第10章 Spring Security 的未来趋势与高级话题(2024 最新版)
19 2
|
8天前
|
安全 Cloud Native Java
第10章 Spring Security 的未来趋势与高级话题(2024 最新版)(上)
第10章 Spring Security 的未来趋势与高级话题(2024 最新版)
23 2
|
8天前
|
安全 Java API
第5章 Spring Security 的高级认证技术(2024 最新版)(上)
第5章 Spring Security 的高级认证技术(2024 最新版)
34 0
|
8天前
|
存储 安全 Java
第3章 Spring Security 的用户认证机制(2024 最新版)(下)
第3章 Spring Security 的用户认证机制(2024 最新版)
32 0
|
8天前
|
存储 安全 Java
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(下)
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(下)
16 0
|
8天前
|
安全 Java 数据库
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(上)
第2章 Spring Security 的环境设置与基础配置(2024 最新版)
34 0
|
8天前
|
安全 Java API
第1章 Spring Security 概述(2024 最新版)(下)
第1章 Spring Security 概述(2024 最新版)
21 0
|
8天前
|
安全 Java 数据安全/隐私保护
第1章 Spring Security 概述(2024 最新版)(上)
第1章 Spring Security 概述(2024 最新版)
27 0