前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot-Security 具体案例、 实现安全框架、权限控制、aop切入

SpringBoot-Security 具体案例、 实现安全框架、权限控制、aop切入

作者头像
宁在春
发布2022-10-31 14:03:43
8860
发布2022-10-31 14:03:43
举报
文章被收录于专栏:关于Java学习@宁在春

SpringBoot-Security 具体案例、 实现安全框架、权限控制、aop切入

SpringBoot-Security介绍

Security 官方序言

​ 安全是一个不断变化的目标,追求一个全面的、系统范围的方法很重要。在安全领域,我们鼓励您采用“安全层”,这样每个层都可以尽可能地保证自身的安全性,并且连续的层提供额外的安全性。每一层的安全性越“严格”,您的应用程序就越健壮和安全。在底层,为了减少中间人攻击,你需要处理诸如传输安全和系统辨识等问题。接下来,您将通常使用防火墙,也许是通过 vpn 或 IP 安全性来确保只有经过授权的系统才能尝试连接。在公司环境中,您可以部署 DMZ 来将面向公共的服务器与后端数据库和应用程序服务器分开。您的操作系统也将发挥关键作用,解决诸如作为非特权用户运行进程和最大化文件系统安全性等问题。操作系统通常也会配置自己的防火墙。希望在某个地方,你可以尝试阻止针对系统的分布式拒绝服务攻击攻击和暴力破解。入侵预防系统安全协议对于监控和响应攻击也特别有用,这样的系统能够采取保护措施,比如实时阻止违规的 TCP/IP 地址。转移到较高的层,您的 Java 虚拟机有望被配置为最小化授予不同 Java 类型的权限,然后您的应用程序将添加自己的问题域特定的安全配置。Spring Security 使后一个领域——应用程序安全性——更加容易。

​ 人们使用 Spring Security 有很多原因,但是大多数人是在发现 Java EE 的 Servlet 规范或 EJB 规范的安全特性之后才开始使用这个项目的,这些特性缺乏典型的企业应用场景所需要的深度。虽然提到了这些标准,但重要的是要认识到它们在 WAR 或 EAR 级别上是不可移植的。因此,如果切换服务器环境,在新的目标环境中重新配置应用程序的安全性通常需要做大量工作。使用 Spring Security 克服了这些问题,并且还为您带来了许多其他有用的、可定制的安全特性。

​ 您可能知道应用程序安全性的两个主要方面是“身份验证”和“授权”(或“访问控制”)。这是 Spring Security 的两个主要目标。“身份验证”是建立一个主体的过程,这个主体就是他们声称的那个人(“主体”通常指一个用户、设备或者其他能够在你的应用程序中执行某个操作的系统)。“授权”是指决定是否允许主体在应用程序中执行操作的过程。为了达到需要作出授权决定的地步,认证过程已经确定了主体的身份。这些概念是常见的,而且根本不是 Spring Security 特有的。

(自己看的时候,蛮喜欢就加在这篇文章的开头拉。)

文章是我在security 5.0.5. RELEASE 版本文档里看到的 。

https://docs.spring.io/spring-security/site/docs/5.0.5.RELEASE/reference/htmlsingle/

文章简介

本文讲的是Spring Boot集成Spring-Security 框架。内容不牵扯到过多具体原理讲解,只是做了简单概述。

适合于初学者,状态大概:对这个不是很懂,但是暂时需要在项目中使用Spring-Boot-Security。

案例里有具体的数据库角色表 、权限表、资源表 是可以切入到已有项目的。

而且是添加注解的方式。

流程、原理等等。我应该也会去写滴,相信我… 对这个东东流程、原理,还是非常好奇的。

当然看完就好奇的就马上去Debug吧 奥利给!!!

项目中有一行代码用到了 jdk 8 中的 Optional 我之前写了文章讲解

这正好是一次实用。 大家可以看一看。

https://blog.csdn.net/weixin_45821811/article/details/115656637

数据库、表

我之前已经写完表的文章。如下

https://blog.csdn.net/weixin_45821811/article/details/115737401

步骤

1、创建Spring-boot项目

​ 工程结构图

2、导入依赖

代码语言:javascript
复制
  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
    </dependencies>

3、yaml配置文件

代码语言:javascript
复制
server:
  port: 8787

spring:
  datasource: #自己的数据库名 自己的数据库密码  
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=false&characterEncoding=utf8&serverTimezone=GMT
    password: 123456
    username: root

4、config

WebConfig

代码语言:javascript
复制
@Configuration  // 相当于springmvc 文件
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("redirect:/login");
    }
}

WebSecurityConfig 安全配置

代码语言:javascript
复制
@Configuration
@EnableWebSecurity  // 开启WebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 这个开启权限注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable(). //屏蔽csrf
                authorizeRequests()
//                .antMatchers("/r/r1").hasAnyAuthority("p1") // 这种是没有开启权限注解 没有添加权限注解的方法
//                .antMatchers("/r/r2").hasAnyAuthority("p2")
//                .antMatchers("/r/r3").hasAnyAuthority("p1","p2")
                .antMatchers("/r/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logout") // 退出url
                .logoutSuccessUrl("/logout-success");  // 自定义登录成功的配置 成功后 转向这个url
    }
}

5、pojo层

​ MyUser 用户

代码语言:javascript
复制
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)// 链式
public class MyUser {
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
}

PermissionDto 资源权限

代码语言:javascript
复制
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)// 链式
public class PermissionDto {
    private String id;
    private String code;
    private String description;
    private String url;
}

6、Dao层

代码语言:javascript
复制
@Mapper
public interface MyUserDao {

    @Select("select * from user_db where username=#{username}")
    Optional<MyUser> getUserByName(String username);

    // 这里是多表联查 查询当前角色拥有的权限  表的结构在我另一篇文章有说明
    @Select("SELECT * FROM t_permission WHERE id IN( SELECT permission_id FROM t_role_permission WHERE role_id IN(SELECT role_id FROM t_user_role WHERE user_id = #{userId} ))")
    List<PermissionDto> findPermissionsByUserId(String userId);
}

7、Service

代码语言:javascript
复制
@Configuration
public class SpringDataMyUserDetailsService implements UserDetailsService {

    @Autowired
    MyUserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<MyUser> user = userDao.getUserByName(username);
        if (user.isPresent()) {// 判空操作  这个是jdk8的一个新特性是 在我一篇文章中有讲
            MyUser myUser = user.get(); // 取出操作

            List<PermissionDto> list = userDao.findPermissionsByUserId(myUser.getId());
            System.out.println("list==>" + list.toString());
            //list==>[PermissionDto(id=1, code=p1, description=测试资源1, url=/r/r1)]

            List<String> permissions = new ArrayList<>();
            list.forEach(p -> permissions.add(p.getCode()));
            System.out.println("permissions===>" + permissions.toString());
            //permissions===>[p1]
            // 这里之所以转成数组 是因为 构建 UserDetails 时
            //.authorities(perarray)  这个添加权限的地方是可以添加一个数组的  更加方便我们个性定
            //参数:权限–此用户的权限(即ROLE_USER,ROLE_ADMIN等)。 不能为空或包含空值
            //		public UserBuilder authorities(String... authorities) {
            //			return authorities(AuthorityUtils.createAuthorityList(authorities));
            //		}


            String[] perarray = new String[permissions.size()];

            permissions.toArray(perarray);
            //创建userDetails
            UserDetails userDetails =
                    User.withUsername(myUser.getUsername()).password( BCrypt.hashpw(myUser.getPassword(), BCrypt.gensalt()) ).authorities(perarray).build();
            return userDetails;
        }
        return null;
    }
}

8、Controller层

代码语言:javascript
复制
@RestController
public class LoginController {

    //后端这返回类型 大家都知道吧 我这里是写的文本  json 是application/json 这种 还有这请求格式 我大都是复制  就不是那种restful 风格拉
    // 大家使用 自行修改哦
    @RequestMapping(value = "/login-success", produces = "text/plain;charset=utf-8")
    public String loginSuccess(){
        return getUsername()+"登录成功";
    }

    @RequestMapping(value = "/logout-success", produces = "text/plain;charset=utf-8")
    public String logout(){
        return "退出成功";
    }


    @RequestMapping(value = "/r/r1", produces = "text/plain;charset=utf-8")
//    @PreAuthorize("isAnonymous()")// 匿名访问
    @PreAuthorize("hasAuthority('p1')" )
    public String r1(){
        return getUsername()+"资源1";
    }
    @RequestMapping(value = "/r/r2", produces = "text/plain;charset=utf-8")
    @PreAuthorize(" hasAuthority('p2')" )
    public String r2(){
        return getUsername()+"资源2";
    }

    @RequestMapping(value = "/r/r3", produces = "text/plain;charset=utf-8")
    @PreAuthorize("hasAuthority('p1') or hasAuthority('p2')" )
    public String r3(){
        return getUsername()+"资源3";
    }

    // 这个是只要认证通过都可以访问 不需要主体带有什么权限
    @RequestMapping(value = "/r/r4", produces = "text/plain;charset=utf-8")
    public String r4(){
        return getUsername()+"资源4";
    }

    private String getUsername(){
        String username=null;
        //当前通过的用户身份
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        if (principal==null){
            username="匿名";
        }
        if(principal instanceof UserDetails){
            UserDetails userDetails=  (UserDetails)principal;
            username = userDetails.getUsername();
        }else{
            username= principal.toString();
        }

        return username;
    }
}

9、启动类

代码语言:javascript
复制
@SpringBootApplication
@MapperScan("com.wyh.dao")
public class SecuritySpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SecuritySpringbootApplication.class, args);
    }

}

接下来就是测试哩。还有我的自言自语…

测试

认证

认证成功

认证错误

退出

授权

admin 有p1 权限 能够访问 /r/r1 资源
admin 没有p2 权限 访问不了 /r/r2 资源
/r/r3 是有p1 权限或者 有p2权限都是能够访问的 但是没有的话是不能访问的
/r/r4 是只要身份认证通过就是能访问的

自言自语

每天记录一下自己的生活 也开始习惯每天这里写写 那里写写的感觉。

写这些一开始是想着方便自己看 但是写着写着就开始想要人来关注来看。

比起一开始随随便便写 现在的话要好一些拉。

就突然想把自己的知道的东西都记录下来,可能是想让人知道吧。

需要学的东西多的多啊。

继续加油哦。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-04-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringBoot-Security 具体案例、 实现安全框架、权限控制、aop切入
    • SpringBoot-Security介绍
      • Security 官方序言
    • 文章简介
      • 数据库、表
        • 步骤
          • 1、创建Spring-boot项目
          • 2、导入依赖
          • 3、yaml配置文件
          • 4、config
          • 5、pojo层
          • 6、Dao层
          • 7、Service
          • 8、Controller层
          • 9、启动类
        • 测试
          • 认证
          • 退出
          • 授权
        • 自言自语
        相关产品与服务
        数据库
        云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档