首页 > 其他分享 >2020-8-12-Spring-Security

2020-8-12-Spring-Security

时间:2024-03-22 17:11:20浏览次数:24  
标签:12 Spring springframework annotation org import Security config security

资源访问控制方式、认证流程、授权流程、快速开始、授权案例、自定义登陆登出页面、会话管理、基于方法的授权

资源访问控制方式

基于角色的访问控制

Role-Based Access Control

基于资源的访问控制(常用)

Resource-Based Access Control


认证流程

UsernamePasswordAuthenticationFilter

用户提交的用户名密码进行封装成Authentication,转发给AuthenticationManager

AuthenticationManager

认证任务委托给DaoAuthenticationProvider

AccessDecisionManager

DaoAuthenticationProvider

调用UserDetailsService获取用户信息、比对用户的密码是否正确,及用户是否拥有权限,将认证结果返回给UsernamePasswordAuthenticationFilter

UserDetailsService

根据用户名进行用户查询,包括用户权限

SecurityContextHolder

将用户的验证信息保存到上下文,用户会话


授权流程

FilterSecuritInterceptor

用户访问受保护的资源,调用SecurityMetadataSource查出当前资源需要的权限,再调用AccessDecisionManager进行授权决策,根据决策结果进行放行或拦截

SecurityMetadataSource

查出当前资源需要的权限

AccessDecisionManager

将用户权限和当前资源所需权限进行比对,通过投票机制决定是否允许用户访问资源

AccessDecisionManager的三个实现类

AffirmativeBased

(1)只要有AccessDecisionVoter的投票为ACCESS_GRANTED则同意用户进行访问

(2)如果全部弃权也表示通过

(3)如果没有一个人投赞成票,但是有人投反对票会抛出AccessDeniedException

ConsensusBades

(1)如果赞成票多于反对票表示通过

(2)如果反对票多于赞成票将抛出AccessDeniedException

(3)如果赞成票和反对票相同或都弃权,且allowIfEqualGrantedDeniedDecisions为true,则表示通过。否则抛出AccessDeniedException

UnanimousBased

(1)如果有一张反对票,抛出AccessDeniedException

(2)如果没有反对票,但是有赞成票,则通过

(3)如果全部弃权,且allowIfEqualGrantedDeniedDecisions为true,则表示通过。否则抛出AccessDeniedException


快速开始

1导入依赖

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

2application.yaml(此案例未配置)

spring:
  security:
    user:
      name: zhanghuan
      password: 123

这样的设置用户的账号密码方式不常用

3定义配置类

package com.example.testtomcat.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig  extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder(){//必须要注入密码编码器
        //return new BCryptPasswordEncoder ();//常用编码器,对密码做加密处理
        return NoOpPasswordEncoder.getInstance ();//此编码器对密码不做处理
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {//指定哪些url需要进行身份验证
        http.authorizeRequests()
                .antMatchers("/hello").authenticated ()//指定url需要进行验证
                .anyRequest().authenticated ()
                .and ()
                .formLogin ();//允许表单登陆
    }
}

4定义查询用户的服务

package com.example.testtomcat.service;

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;

@Service
public class MyUserDetailService implements UserDetailsService {//用户信息处理服务,此服务用来返回用户信息
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {//s参数是传过来的用户名,返回值是用户信息,如果未查到需要手动抛出错误
        UserDetails userDetails= User.withUsername ("zhanghuan").password ("123456").roles ("normalUser").build ();//roles属性和authorities必须二选一,否则报错
        return userDetails;
    }
}

如此配置之后,访问所有资源都需要进行身份验证,验证通过后才可访问资源。退出登陆需访问/logout


授权案例

1给用户授权

package com.example.testtomcat.service;

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;

@Service
public class MyUserDetailService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        UserDetails userDetails= User.withUsername ("zhanghuan").password ("123456").authorities ("p1").build ();//授予p1权限
        return userDetails;
    }
}

2给资源设定访问权限

package com.example.testtomcat.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig  extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder(){
        //return new BCryptPasswordEncoder ();
        return NoOpPasswordEncoder.getInstance ();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/hello").authenticated ()
                .antMatchers ("/resource1").hasAuthority ("p1")//设定访问该资源必须要有p1权限
            	.antMatchers ("/resource2").access ("hasAuthority('p1') and hasAuthority(p2)")//更为灵活的授权方式
                .anyRequest()..permitAll ()
                .and ()
                .formLogin ();
    }
}


自定义登陆登出页面

1自定义登陆页面

package com.example.securitytest.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder(){
        //return new BCryptPasswordEncoder ();
        return NoOpPasswordEncoder.getInstance ();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf ().disable ()
                .authorizeRequests()
                .antMatchers("/hello").authenticated ()
                .antMatchers ("/resource1").hasAuthority ("p1")
                .anyRequest().permitAll ()
                .and ()
                .formLogin ().loginPage ("/login-view").loginProcessingUrl ("/login");
                //这样配置后,登陆页面指向/login-view路径,登陆表单提交的地址指向/login,退出登陆的页面不复存在,但访问/logout会退出登陆(清除session)
    }
}

解决POST请求提交失败

1)屏蔽csrftoken

package com.example.securitytest.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf ().disable ()
    }
}

2)提交的表单中放置csrftoken

<input type="hidden" name="${_csrf.parameterName}" value="{$_csrf.token}"/>

2自定义登出页面

package com.example.securitytest.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .logout()
            .logoutUrl("/logout")//登出地址
            .logoutSuccessUrl("/log-view?logout");//成功跳转
    }
}

会话管理

1会话控制

在WebSecurityConfigurerAdapter的子类中重写方法

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
    }
机制 描述
always 如果没有session存在就创建一个
ifRequired 如果需要就创建一个Session(默认)
never SpringSecurity不创建session,如果其他地方创建就使用它
stateless SpringSecurity不创建session,也不使用session

2会话超时

server.servlet.session.timeout=3600s

3安全会话

server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=true

基于方法的授权

package com.example.securitytest.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)//方法中开启secured、prePost注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder(){
        //return new BCryptPasswordEncoder ();
        return NoOpPasswordEncoder.getInstance ();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf ().disable ()
                .authorizeRequests()
                .antMatchers("/hello").authenticated ()
                .antMatchers ("/resource1").hasAuthority ("p1")
                .antMatchers ("/resource2").access ("hasAuthority('p1') and hasAuthority(p2)")
                .anyRequest().permitAll ()
                .and ()
                .formLogin ().loginPage ("/login-view").loginProcessingUrl ("/login")
                .and ()
                .logout ()
                .logoutUrl ("/logout1")
                .logoutSuccessUrl ("/login-view?logout");
    }

}

在方法上添加授权注解

package com.example.securitytest.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {
    @GetMapping("/index")
    @PreAuthorize ("hasAuthority('PP')")//这里使用prePost
    public String index(Model model){

        model.addAttribute ("name","zhanghuan");
        return "index";
    }
}

注意

未标识授权的方法,不会进行权限验证

标签:12,Spring,springframework,annotation,org,import,Security,config,security
From: https://www.cnblogs.com/sylvesterzhang/p/18089869

相关文章

  • 2020-5-23-Spring
    简介、耦合、控制反转、依赖注入、注解方式反转控制和依赖注入、Spring整合Junit、银行转账案例、代理、AOP面向切面编程、JDBCTemplate简介1核心内容IOC反向控制、AOP面向切面编程2优势方便解耦,简化编程AOP编程支持声明式事务支持方便程序的测试方便集成各种优秀的框架......
  • Spring中getBean的生命周期和整个链路原理
    publicabstractclassAbstractBeanFactoryextendsFactoryBeanRegistrySupportimplementsConfigurableBeanFactory{publicObjectgetBean(Stringname)throwsBeansException{returndoGetBean(name,null,null,false);}protected<T&......
  • 一、SpringBoot基础搭建
    本教程主要给初学SpringBoot的开发者,通过idea搭建单体服务提供手把手教学例程,主要目的在于理解环境的搭建,以及maven模块之间的整合与调用源码:jun/learn-springboot以商城项目为搭建例子,首先计划建1个父模块,3个子模块:父模块(你可以理解为共用模块,约定共用参数以及公用jar等)s......
  • 浮木云学习日志(12)---表格设计(二)
    上次做了一个包括表格的页面设计,个人认为关于表格设计的内容介绍比较笼统,可能没办法直接对这个组件进行透彻的了解,本次我就来详细介绍一下如何通过高级表格设计玩转表格设计。感兴趣的小伙伴可以去他们官网https://www.fumucloud.com/一起体验一下这个高级表格组件。本次记录我们......
  • mysql使用mysqldump.exe导出为sql脚本,进行导入时出现ERROR 1227 (42000) at line 18:
    mysql使用mysqldump.exe导出为sql脚本,进行导入时出现ERROR1227(42000)atline18:Accessdenied;youneed(atleastoneof)theSUPERorSYSTEM_VARIABLES_ADMINprivilege(s)forthisoperation。Warning:ApartialdumpfromaserverthathasGTIDswillbydefaul......
  • SpringBoot3.x与SpringDoc OpenApi之Swagger接口排序
    直接使用Swagger之后,发现所有的Controller接口菜单都是无序的先看一下效果 就是利用了一下SpringDoc提供的接口做了一下自定义排序1.在Controller上加上注解@Tag(name="MenuController",description="1-菜单管理")这里需要注意description属性,在下面的代码里......
  • 解决出现javax.net.ssl.SSLHandshakeException: PKIX path building failed 或 sun.se
    From: https://www.cnblogs.com/luoxiao1104/p/16671501.html当我们从网络上根据url下载文件的时候可能会出现一下异常错误信息: javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:......
  • 「ABC124D」 Handstand
    题意给一个长度为\(n\)的01串\(s\),可以至多进行\(k\)次操作,每次操作可以把任意子串取反,求操作后最长的连续1串长度。分析\(n\)的范围“友好”地告诉我们最大\(O(n\logn)\)。最开始想的是把每一块分出来跑dp,然后发现写不出来\(O(n)\)的式子。(去世)想了一会后注......
  • 基于springboot+vue的乡村民宿管理系统
    一、系统架构        前端:vue|element-ui        后端:springboot|mybatis-plus        环境:jdk1.8+|mysql|maven|nodejs二、代码及数据库        三、功能介绍   01.登录页  02.注册 03.管理员-首页 ......
  • 宠物医院管理系统(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图项目介绍随着宠物行业的快速发展和宠物数量的不断增加,宠物医疗服务的需求日益旺盛。宠物医院管理系统作为一种专业的信息化工具,对于提升宠物医院的工作效率、优化顾客服......