SpringBoot整合SpringSecurity

Spring Security是一个Java框架,用于保护应用程序的安全性。它提供了一套全面的安全解决方案,包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念,可以轻松地集成到任何基于Spring的应用程序中。它支持多种身份验证选项和授权策略,开发人员可以根据需要选择适合的方式。此外,Spring Security还提供了一些附加功能,如集成第三方身份验证提供商和单点登录,以及会话管理和密码编码等。总之,Spring Security是一个强大且易于使用的框架,可以帮助开发人员提高应用程序的安全性和可靠性。

一、创建项目,导入依赖


        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
            <version>2.1.7.RELEASEversion>
        dependency>

二、Spring Security基于数据库认证

要从数据库读取用户信息进行身份认证,需要新建类实现UserDetailService接口重写loadUserByUsername方法:

package com.lin.security.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lin.security.entity.Users;
import com.lin.security.mapper.UsersMapper;
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;

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

    @Autowired
    private UsersMapper usersMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        /* 根据用户名从数据库中查找用户信息,此处结合mybatis plus查询*/
        QueryWrapper<Users> wrapper = new QueryWrapper();
        wrapper.eq("username",s);
        Users users = usersMapper.selectOne(wrapper);
        if (users == null){
            throw new UsernameNotFoundException("用户不存在");
        }

		/* 把用户的权限加到auths中返回,权限可存储到数据库中,从数据库中查询后添加带auths*/
        /* 测试权限*/
        /* List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("user"); */
        /* 测试角色,需要添加前缀ROLE_,无ROLE_则为权限 */
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_user");
        /*返回用户名、密码(加密后)、权限;*/
        /*对从数据库中查询出的密码进行加密,
        new BCryptPasswordEncoder().encode(users.getPassword()),
        建议:推荐把密码加密后再存储到数据库,此处就无需加密操作
        */
        return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths);
    }

}

创建Security的配置类WebSecurityConfig继承WebSecurityConfigurerAdapter,并重写configure(auth)方法:

package com.lin.security.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.builders.HttpSecurity;
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;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;

@Configuration
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)/*从数据库读取的用户进行身份认证*/
        .passwordEncoder(passwordEncoder());/*加密方式*/
    }

	/*对角色的权限——所能访问的路径做出限制*/
    @Override
    protected void configure(HttpSecurity http) throws Exception {

//        退出登录,退出后跳转路径 /test/hello
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll();

        /** 自定义403页面 */
        http.exceptionHandling().accessDeniedPage("/unauth.html");

        http.formLogin()  //自定义登录页面
                .loginPage("/login.html")//登录页面设置
                .loginProcessingUrl("/test/login")//登录访问路径
                .defaultSuccessUrl("/test/index").permitAll()//登录成功之后,跳转路径
                .and().authorizeRequests()
                .antMatchers("/test/hello").permitAll()
//                测试权限,当前登录用户,只有具有admin权限才可以访问这个路径,hasAuthority方法
//                .antMatchers("/test/index").hasAuthority("admin")
//                .antMatchers("/test/index").hasAnyAuthority("admin,user")
//                测试角色
                .antMatchers("/test/index").hasRole("user")
                .anyRequest().authenticated()
                /** 自动登录功能 rememberMe() 记住我  */
                .and().rememberMe().tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(60)  //设置有效时长,60S
                .userDetailsService(userDetailsService)

                .and().csrf().disable(); //关闭csrf防护

    }
	
	/*configure(WebSecurity)用于影响全局安全性
	(配置资源,设置调试模式,通过实现自定义防火墙定义拒绝请求)的配置设置。
	一般用于配置全局的某些通用事物,例如静态资源等*/
	/*public void configure(WebSecurity web) throws Exception {
    	web.ignoring().antMatchers("/resources/**");
	}*/

    /**加密方式*/
    @Bean
    PasswordEncoder passwordEncoder(){
    	/*使用BCrypt加密密码,可自定义加密方式*/
        return new BCryptPasswordEncoder();
    }

}

附加:Spring Security 设置2种加密方式(强散列哈希加密、自定义加密)
PasswordEncoder
SpringBoot整合SpringSecurity_第1张图片

  1. BCryptPasswordEncoder(基于BCrypt的强散列哈希加密)
    基于BCrypt的强散列哈希加密实现,并可以由客户端指定加密的强度strength,强度越高安全性自然就越高,默认为10.
    /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                /*从数据库读取的用户进行身份认证*/
                .userDetailsService(userDetailsService)
                /*加密方法(强散列哈希加密)*/
                .passwordEncoder(new BCryptPasswordEncoder());
    }
  1. 自定义加密
    自定义加密方式,也可以不加密,实现PasswordEncoder接口,重写encode、matches方法
package org.sang.config;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

/**
 * 自定义加密方式
 */
@Component
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {
        return DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes());
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equals(DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes()));
    }
}

Spring Security设置加密方式

    /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                /*从数据库读取的用户进行身份认证*/
                .userDetailsService(userDetailsService)
                /*加密方法(自定义加密方式)*/
                .passwordEncoder(new MyPasswordEncoder());
    }

不加密方式

package com.entity;
 
import cn.hutool.core.util.StrUtil;
import org.springframework.security.crypto.password.PasswordEncoder;
 
public class CustomPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }
 
    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return StrUtil.equals(charSequence, s);
    }
}

三、控制类、Bean

package com.lin.security.controller;

import com.lin.security.entity.Users;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/test")
public class test {

    @GetMapping("/hello")
    public String hello(){

        return "spring Security";
    }

    @PostMapping("/login")
    public String login(){

        return "this your login";
    }

    @GetMapping("/index")
    public String index(){

        return "this your spring Security";
    }

    @GetMapping("/update")
//    @Secured({"ROLE_user","ROLE_person"})
//    单个权限认证
//    @PreAuthorize("hasAuthority('admins')")
//    多个权限认证
//    @PreAuthorize("hasAnyAuthority('admins,person')")
//    单个角色认证
//    @PreAuthorize("hasRole('ROLE_user')")
//    多个角色认证
//    @PreAuthorize("hasAnyRole('ROLE_user,Role_admin')")
    public String update(){

        return "update";
    }

    @GetMapping("/list")
    @PostFilter(value = "filterObject.username=='libai'")
    public List<Users> list(){

        ArrayList<Users> list = new ArrayList<Users>();
        list.add(new Users(1,"libai","666"));
        list.add(new Users(2,"dufeng","123"));
        return list;
    }

    @GetMapping("/info")
    @PreFilter(value = "filterObject.id%2==0")
    public List<Users> info(@RequestBody List<Users> list){

        list.forEach(t->{
            System.out.println(t.getUserid()+"\t"+t.getUsername());
        });

        return list;
    }

}

package com.lin.security.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Users {

    private Integer userid;
    private String username;
    private String password;

}

详情可参考文章

你可能感兴趣的:(spring,boot,spring)