SpringSecurity权限框架(入门篇)

☣SpringSecurity权限管理框架


✧ 什么是安全框架?
解决系统安全问题的框架。如果没有安全框架,我们需要手动处理每个资源的访问控制,非常麻烦。使用安全框架,我们可以通过配置的方式实现对资源的访问限制。


✧ 常用的权限管理框架:
       ✧Spring Security:Spring系列的权限管理框架,内部带有AOP,DI,IOC的功能,约定大于配置的特点,大大的提高了对权限的代码效率,主要是**认证**,和**授权**两个模块。
       ✧Apache Shiro:一个功能强大且易于使用的Java安全框架,提供了认证,授权,加密,和会话管理。


☣⇢目录⇠☣

    • ☣SpringSecurity权限管理框架
        • 一、快速入门
          • 1、入门小案例
          • 2、如何才能使用自定义登录逻辑?
          • 3、如何默认使用自己的login页面
        • 二、知识点解析
          • ①、UserDetailsService详解
          • ②、 PasswordEncoder 密码解析器详解
          • ③、认证过程其他常用配置(内置控制访问方法)
        • 三、角色权限控制
          • 1、权限访问控制
          • 2、角色访问控制
          • 3、访问受限403处理方法


一、快速入门

1、入门小案例

① 新建一个java项目引入依赖

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.2.2.RELEASEversion>
    <relativePath/>
    
  parent>

 
    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-securityartifactId>
    dependency>
    
    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-testartifactId>
      <scope>testscope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintagegroupId>
          <artifactId>junit-vintage-engineartifactId>
        exclusion>
      exclusions>
    dependency>
    <dependency>
      <groupId>org.springframework.securitygroupId>
      <artifactId>spring-security-testartifactId>
      <scope>testscope>
    dependency>

<build>
    <plugins>
      <plugin>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-maven-pluginartifactId>
      plugin>
    plugins>
  build>

② 编写一个resource/static/login.html静态页面准备

DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<form action="/login" method="post">
    用户名:<input type="text" name="userName" /><br/>
    密码:<input type="password" name="passWord" /><br/>
    <input type="submit" value="登录" />
form>
body>
html>

③ 创建启动项目的Start类

@SpringBootApplication
public class SpringSecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityApplication.class);
    }
}

启动测试

SpringSecurity权限框架(入门篇)_第1张图片


SpringSecurity权限框架(入门篇)_第2张图片


总结:SpringSecurity默认需要登录才能访问其他资源,否则全部都会被拦截


2、如何才能使用自定义登录逻辑?

想要自定义用户登录,则需要配置一个SpringSecurityService.java和一个SpringSecurityConfig.java

✧ SpringSecurityService.java:实现接口UserDetailsService,重写loadUserByUsername(String s)方法,在方法里自定义用户(通过这个方法链接数据库进行用户查询)这里定义用户名:admin,密码:123456

@Service
/*自定义用户*/
public class SpringSecurityService implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //判断用户名
        if(StringUtils.isEmpty(s)||!("admin".equals(s))){
            throw new UsernameNotFoundException("不存在此用户!");
        }
        //密码加密
        String pw=passwordEncoder.encode("123456");
        //返回一个用户,以及权限或角色
        return new User(s,pw, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
    }
}

✧ SpringSecurityConfig.java:项目配置文件,内部配置密码加密接口的实现类PasswordEncoder

@SpringBootConfiguration
/*登录页面自定义*/
public class SpringSecurityConfig {
    //配置passwordEncode的实现类
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

SpringSecurity权限框架(入门篇)_第3张图片
SpringSecurity权限框架(入门篇)_第4张图片

总结:这里实现了接口UserDetailsService接口为了自定义用户,使用PasswordEncoder接口类,实现了密码的加密!


3、如何默认使用自己的login页面

修改配置文件需要实现接口WebSecurityConfigurerAdapter类,重写方法configure(HttpSecurity http)进行页面的指定,和权限的拦截。

@SpringBootConfiguration
/*登录页面自定义*/
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    //配置passwordEncode的实现类
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //重写方法配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭csrf
        http.csrf().disable();
        //配置登录页面
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                //登陆成功
                .successForwardUrl("/tomain")
                //登录失败
                .failureForwardUrl("/toagain")
                //配置登录参数
                //.usernameParameter("userName")
                //.passwordParameter("passWord");
        //权限配置
        http.authorizeRequests()
                //以下允许访问
                .antMatchers("/login.html","/login").permitAll()
                //配置其他资源必须登录才能访问
                .anyRequest().authenticated();
    }
}

SpringSecurity权限框架(入门篇)_第5张图片

补充:这里登录成功或者失败跳转内容需要写一个Controller层

@RestController
public class MainController {

    @PostMapping("/tomain")
    public String main(){
        return "欢迎登录";
    }
	
	@GetMapping("login")
    public String toLogin(){
        return "Hello SpringSecurity";
    }

    @PostMapping("/toagain")
    public String toagain(){
        return "登录失败,请重新登录";
    }
}

二、知识点解析

①、UserDetailsService详解

当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。所以我们要通过自定义逻辑控制认证逻辑。如果需要自定义逻辑时,只需要实现 UserDetailsService 接口即可。接口定义如下:
在这里插入图片描述
返回值 UserDetails 是一个接口,定义如下

SpringSecurity权限框架(入门篇)_第6张图片
要想返回 UserDetails 的实例就只能返回接口的实现类,也就是User类,容易与我们平时定义的User类混淆,User类提供很多方法,此处我们使用它的带参构造器。

在这里插入图片描述

  • username :用户名
  • password :密码
  • authorities :用户具有的权限。此处不允许为 null(多个权限用逗号分割

②、 PasswordEncoder 密码解析器详解

当我们使用密码加密时,需要使用接口的实现类,因此需要单独在配置文件中配置指定它的实现类,因为它的实现类过多。
接口介绍:
SpringSecurity权限框架(入门篇)_第7张图片
BCryptPasswordEncoder 是 Spring Security 官方推荐的密码解析器,平时多使用这个解析器。BCryptPasswordEncoder 是对 bcrypt 强散列方法的具体实现。是基于Hash算法实现的单向加密。可以通过strength控制加密强度,默认 10.


测试:》》》》

@SpringBootTest
public class SecurityTest {
    @Test
    public void test(){
        PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
        System.out.println(passwordEncoder.encode("1234"));
    }
}

③、认证过程其他常用配置(内置控制访问方法)

(1)通过Handle修改登录成功和登录失败

  • SecuritySuccessHandle 类(定义成功类通过继承来重写方法onAuthenticationSuccess
@Component
public class SecuritySuccessHandle implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        //设置编码格式
        httpServletRequest.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType("application/json,charset=utf-8");
        httpServletResponse.setCharacterEncoding("utf-8");
        //打印流
        PrintWriter printWriter=null;
        printWriter=httpServletResponse.getWriter();
        printWriter.write("{\"code\":200,\"msg\",\"登陆成功\"}");
    }
}


  • SecurityFailHandle类(定义登录失败类继承重写方法onAuthenticationFailure
@Component
public class SecurityFailHandle implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        //设置编码格式
        httpServletRequest.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType("application/json,charset=utf-8");
        httpServletResponse.setCharacterEncoding("utf-8");
        //打印流
        PrintWriter printWriter=null;
        printWriter=httpServletResponse.getWriter();
        printWriter.write("{\"code\":500,\"msg\",\"登陆失败\"}");
    }
}

  • 修改SpringSecurityConfig配置文件
@SpringBootConfiguration
/*内部访问控制*/
public class SpringSecurityConfig2 extends WebSecurityConfigurerAdapter {
    //引入handle
    @Autowired
    SecuritySuccessHandle securitySuccessHandle;
    @Autowired
    SecurityFailHandle securityFailHandle;

    //配置passwordEncode的实现类
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //重写方法配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭csrf
        http.csrf().disable();
        //配置登录页面
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                //登陆成功handle
                .successHandler(securitySuccessHandle)//Post请求
                //登录失败handle
                .failureHandler(securityFailHandle)
                //配置登录参数
                .usernameParameter("userName")
                .passwordParameter("passWord");
        //权限配置
        http.authorizeRequests()
                //一下允许访问
                .antMatchers("/login.html","/login").permitAll()
                //资源不被任何人访问
                .antMatchers("/denyall.html").denyAll()
                //There was an unexpected error (type=Forbidden, status=403).
                //配置其他资源必须登录才能访问
                .anyRequest().authenticated();//放在最后

    }
}


SpringSecurity权限框架(入门篇)_第8张图片


⭐上面的案例一个实现AuthenticationSuccessHandler成功接口,一个实现失败接口AuthenticationFailureHandler,常用方法:

  • authentication.getAuthorities():获取用户权限信息
  • authentication.getPrincipal():获取用户信息

⭐常用内置控制方法:

  • anyRequest():全部拦截
  • authenticated():需要认证才能访问
  • antMatchers():?(单个字符),*(零个多个字符),**(零个多个目录)
  • permitAll():放行通常与antMatchers()配合使用重点
  • regexMathchers():正则表达式匹配模式eg: .+[.]js
  • anonymous():匿名访问与permitAll相似
  • antMathcher().denyAll():资源不被任何人访问
  • antmatchers().rememberMe():记住我的情况下才能访问我的资源
  • antMatchers().fullyAuthenticated():没记住我访问的资源

三、角色权限控制

SpringSecurity权限框架(入门篇)_第9张图片


1、权限访问控制
  • antMatchers().hasAuthority(String):是否有特定的权限
  • antMatchers().hasAnyAuthority(String…):拥有其中权限有一个即可

修改配置文件SpringSecurityConfig.java

//@SpringBootConfiguration
/*角色权限访问控制*/
public class SpringSecurityConfig3 extends WebSecurityConfigurerAdapter {
    //引入handle
    @Autowired
    SecuritySuccessHandle securitySuccessHandle;
    @Autowired
    SecurityFailHandle securityFailHandle;

    //配置passwordEncode的实现类
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //重写方法配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭csrf
        http.csrf().disable();
        //配置登录页面
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                //登陆成功handle
                .successHandler(securitySuccessHandle)//Post请求
                //登录失败handle
                .failureHandler(securityFailHandle)
                //配置登录参数
                .usernameParameter("userName")
                .passwordParameter("passWord");
        //权限配置
        http.authorizeRequests()
                //设置指定权限
                .antMatchers("/authority.html").hasAuthority("admin")
                //指定某个权限
                .antMatchers("/authority.html").hasAnyAuthority("admin","normal")
                //允许访问
                .antMatchers("/login.html","/login").permitAll()
                //资源不被任何人访问
                .antMatchers("/denyall.html").denyAll()
                //There was an unexpected error (type=Forbidden, status=403).
                //配置其他资源必须登录才能访问
                .anyRequest().authenticated();//放在最后

    }
}

SpringSecurity权限框架(入门篇)_第10张图片

以上用户的权限为no,authority.html需要admin或normal权限的人才能访问。

SpringSecurity权限框架(入门篇)_第11张图片


2、角色访问控制
  • hasRole(String…):有某个角色可以访问
  • hasAnyRole(String…):有某个角色可以访问

修改配置文件SpringSecurityConfig.java

//@SpringBootConfiguration
/*角色权限访问控制*/
public class SpringSecurityConfig3 extends WebSecurityConfigurerAdapter {
    //引入handle
    @Autowired
    SecuritySuccessHandle securitySuccessHandle;
    @Autowired
    SecurityFailHandle securityFailHandle;

    //配置passwordEncode的实现类
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //重写方法配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭csrf
        http.csrf().disable();
        //配置登录页面
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                //登陆成功handle
                .successHandler(securitySuccessHandle)//Post请求
                //登录失败handle
                .failureHandler(securityFailHandle)
                //配置登录参数
                .usernameParameter("userName")
                .passwordParameter("passWord");
        //权限配置
        http.authorizeRequests()
                //指定角色
                .antMatchers("/authority.html").hasRole("QQ")
                //指定某个角色
                .antMatchers("/authority.html").hasAnyRole("AA","BB")
                //允许访问
                .antMatchers("/login.html","/login").permitAll()
                //资源不被任何人访问
                .antMatchers("/denyall.html").denyAll()
                //There was an unexpected error (type=Forbidden, status=403).
                //配置其他资源必须登录才能访问
                .anyRequest().authenticated();//放在最后

    }
}

SpringSecurity权限框架(入门篇)_第12张图片


以上设置只有角色时AA,BB,QQ的人能访问authority.html,这里我们设置的用户时YY角色
SpringSecurity权限框架(入门篇)_第13张图片


3、访问受限403处理方法
  • 实现AccessDeniedHandler接口,自定义一个类处理
  • 配置文件:http.exceptionHandler().accessDeniedHander()

修改配置文件SpringSecurityConfig.java

@SpringBootConfiguration
/*角色权限访问控制*/
public class SpringSecurityConfig3 extends WebSecurityConfigurerAdapter {
    //引入handle
    @Autowired
    SecuritySuccessHandle securitySuccessHandle;
    @Autowired
    SecurityFailHandle securityFailHandle;
    @Autowired
    SecurityAccessDeniedHandler securityAccessDeniedHandler;

    //配置passwordEncode的实现类
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //重写方法配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭csrf
        http.csrf().disable();
        //配置登录页面
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                //登陆成功handle
                .successHandler(securitySuccessHandle)//Post请求
                //登录失败handle
                .failureHandler(securityFailHandle)
                //配置登录参数
                .usernameParameter("userName")
                .passwordParameter("passWord");
        //权限配置
        http.authorizeRequests()
                //设置指定权限
//                .antMatchers("/authority.html").hasAuthority("admin")
                //指定某个权限
//                .antMatchers("/authority.html").hasAnyAuthority("admin","normal")
                //指定角色
                .antMatchers("/authority.html").hasRole("QQ")
                //指定某个角色
                .antMatchers("/authority.html").hasAnyRole("AA","BB")
                //一下允许访问
                .antMatchers("/login.html","/login").permitAll()
                //资源不被任何人访问
                .antMatchers("/denyall.html").denyAll()
                //There was an unexpected error (type=Forbidden, status=403).
                //配置其他资源必须登录才能访问
                .anyRequest().authenticated();//放在最后

//        对403情况的处理
                http.exceptionHandling()
                        .accessDeniedHandler(securityAccessDeniedHandler);
    }
}

自定义处理类:SecurityAccessDeniedHandler.java

@Component
public class SecurityAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        //设置响应编码
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType("application/json,charset=utf-8");
        //打印流
        PrintWriter printWriter=null;
        printWriter=httpServletResponse.getWriter();
        printWriter.write("{\"code\",403,\"msg\",\"权限不足请找管理员!\"}");
    }
}

测试结果:
SpringSecurity权限框架(入门篇)_第14张图片


你可能感兴趣的:(Java+大数据之旅,框架,java,SpringSecurity)