简介SpringSecurity+Spring Boot整合

Spring Security

一、Spring security简介

spring security 的核心功能主要包括:

  • 认证(你是谁)
  • 授权(你能做什么)
  • 攻击防护(防止伪造身份)

其核心就是一组过滤器链,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QDSKdhh0-1642412252279)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20220114173759485.png)]

比如,对于username,password认证过滤器来说

  1. 检查是否是一个登录请求
  2. 是否包含username和password(也就是该过滤器需要的一些认证信息)
  3. 如果不满足则放行给下一个

​ 下一个按照自身职责判定是否是自身需要的信息,basic的特征就是在请求头中有 Authorization:Basic eHh4Onh4 的信息。中间可能还有更多的认证过滤器。

​ 最后一环是 FilterSecurityInterceptor,这里会判定该请求是否能进行访问rest服务,判断的依据是 BrowserSecurityConfig中的配置,如果被拒绝了就会抛出不同的异常(根据具体的原因)。

​ Exception Translation Filter 会捕获抛出的错误,然后根据不同的认证方式进行信息的返回提示。

注意:绿色的过滤器可以配置是否生效,其他的都不能控制。

​ Spring非常流行和成功的java引用开发框架,SpringSecurity正是Spring家族中的成员。Spring Security基于Spring框架,提供了一套Web应用安全性的完整解决方案。

​ 正如你可能知道的关于安全方面的两个主要区域是"认证"和"授权"(或者访问控制),一般来说Web应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两部分,这两点也是SpringSecurity重要核心功能。

  • 用户认证(Authentication):验某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码,系统通过校验用户名和密码来完成认证过程,通俗点说就是系统任务用户是否能都登录
  • 用户授权(Authorization):指的是验证某个用户是否有权限执行某个操作,在一个系统中,不同用户所具有的权限是不同的,比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改,一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。通俗点讲就是

使用实例

1、通过配置类设定登录用户
1.1、pom.xml文件
	<!--Spring Security依赖添加-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
1.2、配置文件WebSecurityConfig
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //创建密码编码器
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        //
        auth.inMemoryAuthentication().passwordEncoder(bCryptPasswordEncoder)
            	//设置用户名密码(若passwordEncoder中设置了密码编辑器,则设置密码时要设置密码编辑器)
      		    //.roles("") 方法设置角色
                .withUser("admin")
                .password(bCryptPasswordEncoder.encode("123123")).roles("ADMIN","USER")
                .and()
                .withUser("user")
                .password(bCryptPasswordEncoder.encode("123123")).roles("USER")
                .and()
                .withUser("tmp")
                .password(bCryptPasswordEncoder.encode("123123")).roles();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //获取Http的设置authorizeRequests授权请求方法
        //antMatchers添加无需授权请求permitAll()设置为全部用户允许
        //.anyRequest().authenticated() 其他请求都需要认证
        http.authorizeRequests()
                //添加/product/** 下的所有请求只能由user角色才能访问
                .antMatchers("/product/**").hasRole("USER")
                //添加/admin/** 下的所有请求只能由admin角色才能访问
                .antMatchers("/admin/**").hasRole("ADMIN")
                //没有定义的请求,所有的角色都可以访问(tmp也可以)
                .anyRequest().authenticated()
            .and()
                //当不知设登录页面时,使用的时默认的登录页面
                .formLogin()
            /*
            //设置登录页面为login  默认情况下为自带的默认登录页面
                .loginPage("/login")
                //所有人均可允许
                .permitAll()
                 
            .and().logout()
            	//logoutUrl("/logout"); 设置注销路径
                //默认情况是,访问URL”/ logout”,使HTTP Session无效来清除用户,
                //  清除已配置的任何#rememberMe()身份验证,清除SecurityContextHolder,
                //  然后重定向到”/login?success”
                //登录后所有人均可访问
                .permitAll();
            */
            .and()
                .httpBasic();
    }
}
2、结合数据库中的用户信息
2.1、Pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.12.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.erha.springsecurity</groupId>
	<artifactId>springsecuritydemo03</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springsecuritydemo03</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<!--Spring Security依赖添加-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!--数据库连接-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

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

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

2.2、配置文件application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/jqdatatset?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

  #  spring data jpa 相关配置
  jpa:
    database: mysql
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    show-sql: true
    hibernate:
      ddl-auto: update
2.3、主启动类
@SpringBootApplication
@ComponentScan(basePackages = "com.erha.springsecurity")
@EnableJpaRepositories(basePackages = "com.erha.springsecurity.dao")
@EntityScan(basePackages = "com.erha.springsecurity.entity")
public class Springsecuritydemo03Application {

	public static void main(String[] args) {
		SpringApplication.run(Springsecuritydemo03Application.class, args);
	}

}
2.4、entity对象类
@Entity
@Table(name = "user")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
    @Id
    @GenericGenerator(name = "idGenerator",strategy = "uuid")
    @GeneratedValue(generator = "idGenerator")
    private String id;

    @Column(name = "login",unique = true,nullable = false,length = 64)
    private String login;

    @Column(name = "password",nullable = false,length = 64)
    private String password;

    @Column(name = "role",nullable = false,length = 64)
    private String role;

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                ", login='" + login + '\'' +
                ", password='" + password + '\'' +
                ", role='" + role + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (id != null ? !id.equals(user.id) : user.id != null) return false;
        if (login != null ? !login.equals(user.login) : user.login != null) return false;
        if (password != null ? !password.equals(user.password) : user.password != null) return false;
        return role != null ? role.equals(user.role) : user.role == null;
    }

    @Override
    public int hashCode() {
        int result = id != null ? id.hashCode() : 0;
        result = 31 * result + (login != null ? login.hashCode() : 0);
        result = 31 * result + (password != null ? password.hashCode() : 0);
        result = 31 * result + (role != null ? role.hashCode() : 0);
        return result;
    }
}

2.5、dao层User对应的Repostory
@Repository
public interface UserRepository extends JpaRepository<User,String> {
    User findUserByLogin(String login);
}
2.6、Service层UserDetailsService实现类
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private UserRepository userRepository;
    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
        User user = userRepository.findUserByLogin(login);

        if(user == null){
            throw new UsernameNotFoundException("User "+login+" was not found in db");
        }

        //设置角色
        Collection<GrantedAuthority> objects = new ArrayList<>();
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(user.getRole());
        objects.add(grantedAuthority);

        //第二个参数为密码,若存在密码编码器,需要再次使用密码编码器
        /*
         * 参数说明
         * 1、username 用户名参数
         * 2、password 用户密码 设置密码编辑器后,可在此设置密码编辑器
         * 3、Collection<? extends GrantedAuthority> authorities  用户所有角色
         **/
        return new org.springframework.security.core.userdetails.User(login, bCryptPasswordEncoder.encode(user.getPassword()),objects);
    }
}

2.7、WebSecurity配置类
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;

    @Override
    //关于用户的设置
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService) //设置自定义userDetailsService
                .passwordEncoder(passwordEncoder());
    }

    @Override
    //页面校验设置
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/product/**").hasRole("USER")
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()//任何角色都可以完成
                .and()
                .formLogin()
                .and()
                .httpBasic()
                .and().logout().logoutUrl("/logout");
    }

    @Bean // 定义密码编码器
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
2.8、Controller层

AdminController类

@RestController
@RequestMapping(value = "/admin")
public class AdminController {

    @RequestMapping(value = "/hello.do")
    public String hello(){
        return "admin hello";
    }
}

ProductController

@RestController
@RequestMapping(value = "/product")
public class ProductController {

    @RequestMapping(value = "/hello.do")
    public String hello(){
        return "product hello";
    }
}
补充
1、修改当前登录用户密码

若涉及到要修改当前登录用户密码的情况,可用如下方法进行编写

重点是:若使用了密码编码器 在密码更新时,要将更新密码使用密码编码器进行编码

@Mapper
@Repository
public interface UserMapper {
 ...
 @Update("update user set password = #{newPwd} where username = #{username}")
    int updatePwd(String username, String newPwd);
}
UserInfoService.java类中添加更新密码的操作方法:

@Service
public class UserInfoService { 
    ...
    public int updatePwd(String oldPwd, String newPwd) {
        // 获取当前登录用户信息(注意:没有密码的)
        UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String username = principal.getUsername();

        // 通过用户名获取到用户信息(获取密码)
        UserInfo userInfo = userInfoMapper.getUserInfoByUsername(username);

        // 判断输入的旧密码是正确
        if (passwordEncoder.matches(oldPwd, userInfo.getPassword())) {
            // 不要忘记加密新密码
            return userInfoMapper.updatePwd(username, passwordEncoder.encode(newPwd));
        }
        return 0;
    }
}
2、注解完成控制层方法的权限访问

@PreAuthorize(“hasAnyRole(‘user’)”)

@RestController
public class HelloController {
    @Autowired
    private UserInfoService userInfoService;

    @GetMapping("/get-user")
    public UserInfo getUser(@RequestParam String username){
        return userInfoService.getUserInfo(username);
    }

    @PreAuthorize("hasAnyRole('USER')") // 只能user角色才能访问该方法
    @GetMapping("/user")
    public String user(){
        return "user角色访问";
    }

    @PreAuthorize("hasAnyRole('ADMIN')") // 只能admin角色才能访问该方法
    @GetMapping("/admin")
    public String admin(){
        return "admin角色访问";
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值