• springboot整合springsecurity


    1.快速入门

    1.1 安装依赖

    创建springboot项目,在pom.xml配置如下依赖,注:ssm整合springsecurity可见文章:https://www.cnblogs.com/fqh2020/p/11973856.html

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

    1.2 编写controller

    新建一个测试controller

    package com.gh.springsecuritydemo.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Author Eric
     * @Date 2021/7/4 19:15
     * @Version 1.0
     */
    @RestController
    @RequestMapping("admin")
    public class TestController {
    
        @GetMapping("hello")
        public String test1(){
            return "hello security";
        }
    }

    1.3 启动项目

    当启动项目的时候,spring security 会默认为我们生成一个password 并打印在控制台,例如:

    Using generated security password: db83be86-bc15-4470-83ac-d56679a05924

    访问url 时spring security 会默认进行拦截并跳转到它的登录界面 

     这时我们用spring security默认提供的用户名 user 和自动生成的密码进行登录,就可以访问到对应的页面了

    2.设置登录的用户名和密码

    2.1 通过配置文件

    spring.security.user.name=root
    spring.security.user.password=root

    2.2 通过配置类

    package com.gh.springsecuritydemo.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @Author Eric
     * @Date 2021/7/4 22:45
     * @Version 1.0
     */
    @Configuration
    public class SpringsecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception{
            BCryptPasswordEncoder bCryptPasswordEncoder=new BCryptPasswordEncoder();
            String password = bCryptPasswordEncoder.encode("123");
            auth.inMemoryAuthentication().withUser("tom").password(password).roles("admin");
        }
    
        @Bean
        PasswordEncoder password(){
            return new BCryptPasswordEncoder();
        }
    }

    2.3 自定义编写实现类

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

    package com.gh.springsecuritydemo.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @Author Eric
     * @Date 2021/7/4 23:09
     * @Version 1.0
     */
    @Configuration
    public class SecurityConfig 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();
        }
    }

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

    package com.gh.springsecuritydemo.service;
    
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.AuthorityUtils;
    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.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    /**
     * @Author Eric
     * @Date 2021/7/4 23:14
     * @Version 1.0
     */
    @Service("userDetailsService")
    public class MyUserDetailService implements UserDetailsService {
        @Override
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
            List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("role");//权限
            return new User("mary", new BCryptPasswordEncoder().encode("123"), auth);
        }
    }

    3.整合mybatisplus

    3.1 导入依赖

            <!-- 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>

    3.2 编写配置

    # mysql数据库连接
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=root

    3.3 修改service层

    启动类上加上注解@MapperScan

    package com.gh.springsecuritydemo.service;
    
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.gh.springsecuritydemo.enetity.Users;
    import com.gh.springsecuritydemo.mapper.UsersMapper;
    import lombok.Data;
    import lombok.RequiredArgsConstructor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.AuthorityUtils;
    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.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    /**
     * @Author Eric
     * @Date 2021/7/4 23:14
     * @Version 1.0
     */
    @Service("userDetailsService")
    @RequiredArgsConstructor
    public class MyUserDetailService implements UserDetailsService {
    
        private final UsersMapper usersMapper;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            //根据用户名查询数据
            QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("username", username);
            Users user = usersMapper.selectOne(queryWrapper);
            if (user == null) {
                throw new UsernameNotFoundException("用户名不存在");
            }
            List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("role");//权限
            return new User(user.getUsername(), new BCryptPasswordEncoder().encode(user.getPassword()), auth);
        }
    }

    4.自定义登录界面

    4.1 配置登录页

    在配置类重写configure方法

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin()   //自定义自己编写的登录页面
                    .loginPage("/login.html")
                    .loginProcessingUrl("/user/login") //登录访问路径
                    .defaultSuccessUrl("/admin/index").permitAll()  //登录成功跳转的路径
                    .and().authorizeRequests()
                    .antMatchers("/","/admin/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
                    .anyRequest().authenticated() //所有请求都可以访问
                    .and().csrf().disable();  //关闭csrf防护
        }

    4.2 编写登录页

    无需编写action对应url

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

    5.1 hasAuthority方法

    hasAuthority只针对某一个权限

    在配置类设置当前地址有哪些权限可以访问

    5.2 hasAnyAuthority方法

    hasAnyAuthority可以匹配多个权限

    逗号进行分隔权限

    5.3 hasRole方法

    如果用户给定角色允许访问,否则出现403

    如果当前用户具有指定角色,返回true

     在service需要加上前缀ROLE_

    5.4 hasAnyRole方法

    该方法可以匹配多个角色

     匹配

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

    在configure中配置没有访问权限页面

            //配置自定义访问权限页面
            http.exceptionHandling().accessDeniedPage("/unauth.html");
    

    6.用户授权(注解使用)

    6.1 @Secured

    用户具有某个角色,可以访问方法

    启动类加上 @EnableGlobalMethodSecurity(securedEnabled = true) 注解,代表启动注解配置

        @GetMapping("update")
        @Secured({"ROLE_sale","ROLE_manager"})
        public String update(){
            return "hello update";
        }

    在userDetailService设置角色

    List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_sale");//权限

    6.2 @PreAuthorize

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

        @GetMapping("update")
        @PreAuthorize("hasAnyAuthority('sale')")
        public String update(){
            return "hello update";
        }

    6.3 @PostAuthorize

    在方法执行之后再进行权限验证

    启动类加上 @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) 注解

        @GetMapping("update")
        @PostAuthorize("hasAnyAuthority('sales')")
        public String update(){
            System.out.println(111);
            return "hello update";
        }

    6.4 @PostFilter&@PreFilter

    @PosterFilter 代表方法返回数据进行过滤

    @PreFilter 代表方法传入数据进行过滤

    7.用户退出

    在配置类进行配置

         //退出配置
            http.logout().logoutUrl("/logout").logoutSuccessUrl("/admin/hello").permitAll();

    8.自动登录

    8.1 配置数据源

    在配置类中进行配置

        //注入数据源
        @Autowired
        private DataSource dataSource;
    
        @Bean
        public PersistentTokenRepository persistentTokenRepository(){
            JdbcTokenRepositoryImpl jdbcTokenRepository=new JdbcTokenRepositoryImpl();
            jdbcTokenRepository.setDataSource(dataSource);//配置数据源
            jdbcTokenRepository.setCreateTableOnStartup(true);//自动创建表
            return jdbcTokenRepository;
        }

    8.2 配置自动登录

    8.3 修改前端登录页面

    添加一个复选框,指定name必须为remember-me

    9.CSRF

      跨站请求伪造通常缩写为CSRF,是一种挟制用户在当前已登录的web应用程序上执行非本意的操作的攻击方法,跟跨网站脚本(XSS)相比,XSS是利用用户对指定网站的信任,CSRF利用的是网站对用户网页浏览器的信任.

      跨站请求攻击,简单的说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作,(如发邮箱,发消息,转账),由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行,这利用了web身份认证的一个漏洞,简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出来的.

    一点点学习,一丝丝进步。不懈怠,才不会被时代所淘汰!

  • 相关阅读:
    POJ1486 Sorting Slides 二分图or贪心
    POJ2060 Taxi Cab Scheme 最小路径覆盖
    POJ3083 Children of the Candy Corn 解题报告
    以前的文章
    POJ2449 Remmarguts' Date K短路经典题
    这一年的acm路
    POJ3014 Asteroids 最小点覆盖
    POJ2594 Treasure Exploration 最小路径覆盖
    POJ3009 Curling 2.0 解题报告
    POJ2226 Muddy Fields 最小点集覆盖
  • 原文地址:https://www.cnblogs.com/fqh2020/p/14970407.html
Copyright © 2020-2023  润新知