Spring Security

Spring Security

框架简介

概要

​ Spring Security基于Spring框架,提供了一套Web应用安全性的完整解决方案,用户认证和用户授权是Spring Security重要核心功能

​ 用户认证:系统认为用户能否登录

​ 用户授权:系统判断用户是否有权限去做某些事情

与Shiro对比

​ SPring Security特点:

  • ​ 和Spring无缝整合
  • ​ 全面的权限控制
  • ​ 专门为Web开发而设计
  • ​ 旧版本不能脱离Web环境使用
  • ​ 新版本对整个框架进行了分成抽取,分成了核心模块和Web模块。单独引入核心模块就可以脱离Web环境
  • ​ 重量级

Shiro

  • ​ 轻量级。Shiro主张的理念是吧复杂的事情简单化,针对对性能有更高要求的互联网应用有更好的表现

  • ​ 通用性

  • ​ 好处:不局限于Web环境,可以脱离Web环境使用

  • ​ 缺陷:在Web环境下一些特定的需求需要手动编写代码定制

    Security基本原理

    SpringSecurity本质上是一个过滤器链,有很多过滤器

    代码底层流程,重点看三个过滤器

    FilterSecurityInterceptor:是一个方法及的过v零七,基本位于过滤链的最低端

    ExceptionTranskationFilter:是异常过滤器,用来处理在认证授权过程中抛出的异常

    UserbanePasswirdAuthenticationFilter:对login的POST请求做拦截,校验表单中用户名和密码

入门案列

创建正常的Springboot工程

引入相关依赖

<!--SpringSecSecurity-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

编写controller进行测试

@Controller
public class Contriller {

    @RequestMapping("/hello")
    @ResponseBody()
    public String hello(){
        return "hello";
    }
}

运行成功后,会出现本次登录的密码
请添加图片描述
然后访问方法,会出现登录界面,输入密码,即可成功访问
请添加图片描述
两个重要的接口

UserDetallService接口:查询数据库用户名和密码过程

​ 创建类继承UsernamePasswordAuthenticationFilter,重写方法

​ 创建类实现UserDetailService,编写拆线呢数据过程,返回User对象,这个user对象是安全框架提供对象

PasswordEncoder接口:数据加密接口,用于返回User对象里面的密码加密

Web权限方案

认证

1、设置登录的用户名和密码

​ 第一种方式:通过配置文件

​ 在application.properties中填写配置文件
请添加图片描述
第二种方式,通过配置类

​ 创建config包,在包中创建SecurityConfig类,用来配置信息

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        对密码进行加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("123456");
//        设置账号密码
        auth.inMemoryAuthentication().withUser("zhangsan").password(password).roles("admin");
    }

//    实现加密接口
    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

​ 第三种方式,自定义编写实现类

​ 第一步 创建配置类,设置使用那个userDetailsService实现类

@Configuration
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {

//    获取存储密码的UserDetailsService对象
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        从userDetailsService中获取密码,并加密
        auth.userDetailsService(userDetailsService).passwordEncoder(password());

    }

//    实现加密接口
    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
}

​ 第二步编写实现类,返回User对象,User对象有用户名密码和操作权限

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//        获取用户的角色(权限)
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
//        返回用户信息,用户名,密码,角色
        return new User("lisi",new BCryptPasswordEncoder().encode("123456"),auths);
    }
}
查询数据库完成用户认证

第一步 引入相关依赖

<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok 用来简化实体类-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

第二步 创建数据库和数据表

第三步 创建与数据表对应的实体类

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
}

第四步 整合mapper,创建接口,继承MybatisPlus的mapper的接口

@Repository
public interface UserMapper extends BaseMapper<User> {
}

第五步 在UserDetailsService调用mapper里面的方法查询数据库进行用户认证

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//        从数据库中查询用户名对应的密码
//        设置条件查询
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        wrapper.eq("username",username);
        User user=userMapper.selectOne(wrapper);
        if(user==null){
            throw new UsernameNotFoundException("用户名不存在");
        }
//        获取用户的角色(权限)
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
//        返回用户信息,用户名,密码,角色
        return new org.springframework.security.core.userdetails.User(username,new BCryptPasswordEncoder().encode(user.getPassword()),auths);
    }
}

第六步 在启动类上添加扫描注解 MapperScan

@SpringBootApplication
@MapperScan("com.springsecuritty.mapper")
public class Application {

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

}

第七步 配置数据库信息

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/userinfo?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=shou00736
自定义用户登录界面

1、在配置类中实现相关配置

//    重写自动跳转到登录的方法
    @Autowired
    protected void configure(HttpSecurity http) throws Exception {
       http.formLogin() //自定义自己编写的登录页面
        .loginPage("/lofin.html") //设置需要跳转的登录页面
        .loginProcessingUrl("/user/login") //登录访问路径
        .defaultSuccessUrl("/test/index").permitAll() //设置登录成功后访问的路径
        .and().authorizeRequests()
               .antMatchers("/","/test/hello","user/login").permitAll()//设置可以直接访问的,不需要认证的地址
        .anyRequest().authenticated().and().csrf().disable();//关闭csrf的保护
    }

2、创建相关前端登录页面和跳转的controller方法

<form action="/user/login" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
@RequestMapping("/test/index")
@ResponseBody
public String index(){return "index";}

授权

基于角色或权限进行访问控制

第一个方法:hasAuthority方法(针对用户只拥有一个权限)

​ 如果当前的主题具有指定的权限,则返回true否则返回false

//    重写自动跳转到登录的方法
    @Autowired
    protected void configure(HttpSecurity http) throws Exception {
       http.formLogin() //自定义自己编写的登录页面
        .loginPage("/login.html") //设置需要跳转的登录页面
        .loginProcessingUrl("/user/login") //登录访问路径
        .defaultSuccessUrl("/test/index").permitAll() //设置登录成功后访问的路径
        .and().authorizeRequests()
               .antMatchers("/","/hello","/user/login").permitAll()//设置可以直接访问的,不需要认证的地址
               //当前登录用户,只有具有admins权限才可以访问这个路径
               .antMatchers("/test/index").hasAuthority("admins")
        .anyRequest().authenticated().and().csrf().disable();//关闭csrf的保护
    }

第二个方法:hasAnyAuthority方法(针对用户拥有多个权限)

​ 如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的化,返回true

//    重写自动跳转到登录的方法
    @Autowired
    protected void configure(HttpSecurity http) throws Exception {
       http.formLogin() //自定义自己编写的登录页面
        .loginPage("/login.html") //设置需要跳转的登录页面
        .loginProcessingUrl("/user/login") //登录访问路径
        .defaultSuccessUrl("/test/index").permitAll() //设置登录成功后访问的路径
        .and().authorizeRequests()
               .antMatchers("/","/hello","/user/login").permitAll()//设置可以直接访问的,不需要认证的地址
               //当前登录用户,只有具有admins权限才可以访问这个路径
               .antMatchers("/test/index").hasAnyAuthority("admins,rule")
        .anyRequest().authenticated().and().csrf().disable();//关闭csrf的保护
    }
}

第三种方法:hasRole方法

​ 如果当前主体具有指定的角色,则返回true

第四种方法:hasAnyRole方法

​ 表示用户具有任何一个条件都可以访问

注意:使用后面两种方法,在源码中会在权限名称前+ROLE_

自定义403没有权限访问页面

在配置类中进行配置

//    重写自动跳转到登录的方法
    @Autowired
    protected void configure(HttpSecurity http) throws Exception {
//        配置没有权限访问跳转自定义界面      		
        http.exceptionHandling().accessDeniedPage("/unauth.html");
    }

微服务权限方案

原理总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值