当前位置:   article > 正文

SpringSecurity入门、注解、配置_使用spring security启动类注解

使用spring security启动类注解

SpringSecurity

Web安全方面的两个主要区域“用户认证(Authentication)”,“用户授权(Authorization)

1、SpringSecurity特点:

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

2、Shiro特点

  • 轻量级,针对对性能有更高要求的互联网应用有更好的表现
  • 通用性
    • 好处:不局限与web环境
    • 缺陷:在web环境下一些特定的需求需要动手编写代码定制

3、常见的安全管理技术栈的组合

  • SSM+Shiro
  • springboot/springcloud+springSecurity

4、入门案例

  • 创建springboot工程
  • 引入相关依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 编写controller进行测试
@RestController
@RequestMapping("/test")
public class TestController {
    @GetMapping("/show")
    public String show(){
        return "hello security";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

5、UserDetailsService接口

当什么都不配置的时候SpringSecurity的账号密码是自动生成的,实际开发中需要去数据库中查询,我们要通过自定义逻辑控制认证逻辑!

需要自定义逻辑时,只需要实现UserDetailsService接口即可

UserDetailsService接口用来查数据库

用法:

* 创建类继承UsernamePasswordAuthenticationFilter,重写attemptAuthentication、successfulAuthentication、unsuccessfulAuthentication三个方法
* 创建类实现UserDetailsService,编写查询数据过程,返回User对象,这个User对象是安全框架提供的对象
  • 1
  • 2

6、PasswordEncoder接口

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

7、设置登录的用户名和密码的三种方式

7.1、通过配置文件

  • application.yml
spring:
  security:
    user:
      name: username
      password: password
  • 1
  • 2
  • 3
  • 4
  • 5

7.2、通过配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        加密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encodePwd = bCryptPasswordEncoder.encode("123123");
        auth.inMemoryAuthentication().withUser("zzl").password(encodePwd).roles("admin");
    }


//   加密过程中需要用到PasswordEncoder对象
    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

7.3、自定义实现类设置

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

@Configuration
public class SecurityConfig3 extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
    }

    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Collection<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User("zzl",new BCryptPasswordEncoder().encode("000000"),auths);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

8、查询数据库完成用户认证

1、整合Mybatis-plus 完成数据库操作

  • 引入相关依赖
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2、创建数据库,数据库表

create DATABASE securityDemo;
use securityDemo;
create table users(
	id int primary key,
	username varchar(30) not null,
	password varchar(30) not null
);
insert into users values(1,'zzl','zzl'),(2,'lll','lll');
select * from users;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3、创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
    private int id;
    private String username;
    private String password;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4、整合Mybatis-plus,创建接口,继承BaseMapper接口

public interface UsersMapper extends BaseMapper<Users> {

}
  • 1
  • 2
  • 3

5、在MyUserDetailsService调用Mapper里的方法查询数据库进行用户认证

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

    @Autowired
    private UsersMapper usersMapper;

    @Override
    public UserDetails loadUserByUsername(String username ) throws UsernameNotFoundException {
        QueryWrapper<Users> wrapper= new QueryWrapper<>();
        wrapper.eq("username",username);
        Users user = usersMapper.selectOne(wrapper);
        if(user == null){
            throw new UsernameNotFoundException("用户名不存在!");
        }
        Collection<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User(user.getUsername(),new BCryptPasswordEncoder().encode(user.getPassword()),auths);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

6、在启动类上加入@MapperScan注解

9、自定义登录页面

在sercurity配置类中重写**configure(HttpSecurity http)**方法

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().loginPage("/login.html") //  自定义登录页面
                .loginProcessingUrl("/user/login")//登录页面的数据提交的URL
                .defaultSuccessUrl("/test/index").permitAll()//登录成功之后,跳转路径
                .and().authorizeRequests()
                .antMatchers("/","/user/login","/test/show").permitAll()//设置哪些路径可以直接访问
                .anyRequest().authenticated()
                .and().csrf().disable();//关闭csrf防护
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

10.1、hasAuthority方法

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

测试

在sercurity配置类中配置指定路径的访问权限

protected void configure(HttpSecurity http) throws Exception {
        ...
      .antMatchers("/test/index").hasAuthority("admins")//给指定的路径设置指定的权限
		...
    }
  • 1
  • 2
  • 3
  • 4
  • 5

10.2、hasAnyAuthority方法

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

protected void configure(HttpSecurity http) throws Exception {
        ...
      .antMatchers("/test/index").hasAnyAuthority("admins","manager")//给指定的路径设置指定的权限
		...
    }
  • 1
  • 2
  • 3
  • 4
  • 5

10.3、hasRole方法

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

protected void configure(HttpSecurity http) throws Exception {
        ...
      .antMatchers("/test/index").hasRole("sale")//给指定的路径设置指定的角色
		...
    }
  • 1
  • 2
  • 3
  • 4
  • 5

注意在业务层给用户添加角色时,必须以’ROLE_'开头

Collection<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_sale");
  • 1

10.4、hasAnyRole方法

如果当前主体具备指定的任意角色,则返回true

protected void configure(HttpSecurity http) throws Exception {
        ...
      .antMatchers("/test/index").hasAnyRole("sale","role")//给指定的路径设置指定的角色
		...
    }
  • 1
  • 2
  • 3
  • 4
  • 5

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

在sercurity配置类中配置指定路径的访问权限

protected void configure(HttpSecurity http) throws Exception {
    //设置没有访问权限的错误页面
        http.exceptionHandling().accessDeniedPage("/unauth.html");
    }
  • 1
  • 2
  • 3
  • 4

12、注解的使用

12.1、@Secured

判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀ROLE_

需要先开启使用注解的功能

@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecuritydemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SecuritydemoApplication.class, args);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在指定的方法添加注解

@Secured({"ROLE_sale2"})
@GetMapping("/index")
public String index(){
    return "hello index";
}
  • 1
  • 2
  • 3
  • 4
  • 5

12.2、@PreAuthorize

需要先开启使用注解的功能

@EnableGlobalMethodSecurity(prePostEnabled = true)
  • 1

@PreAuthorize注解适合进入方法前的权限认证

@PreAuthorize可以将登陆用户的roles/permissions参数传到方法中

12.3、@PostAuthorize

需要先开启使用注解的功能

@EnableGlobalMethodSecurity(prePostEnabled = true)
  • 1

@PostAuthorize注解使用的并不多,在方法执行后在进行权限验证,适合验证带有返回值的权限

13、用户注销

在配置类中添加退出映射地址

protected void configure(HttpSecurity http) throws Exception {
    ...
        //用户注销的地址,注销成功后访问的地址
  http.logout().logoutUrl("/user/logout").logoutSuccessUrl("/test/index").permitAll();
	...
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

14、基于数据库的自动登录

cookie技术是将数据存储到客户端,不安全

创建表

security可以自动创建

//手动创建
create table persistent_logins (
		username varchar(64) not null, 
		series varchar(64) primary key, 
		token varchar(64) not null, 
		last_used timestamp not null
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在security配置类中添加数据源,配置操作数据库对象

//    注入数据源
    @Autowired
    private DataSource dataSource;

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
//        自动创建表
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

配置自动登录

@Override
    protected void configure(HttpSecurity http) throws Exception {
		...
        .and().rememberMe().tokenRepository(persistentTokenRepository())
            .tokenValiditySeconds(60)//设置有效时长
            .userDetailsService(userDetailsService)
		...
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在登录界面添加复选框

<form method="post" action="/user/login">
    用户名:<input type="text" name="username"/>
    密码:<input type="text" name="password"/>
    <input type="checkbox" name="remember-me"/>自动登录
    <input type="submit" name="login"/>
</form>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

15、CSRF理解

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/953465
推荐阅读
相关标签
  

闽ICP备14008679号