SpringSecurity理解
SpringSecurity的重要核心功能是: 用户授权、用户认证
特点
- 和Spring无缝整合
- 全面的权限控制
- 专门为Web开发而设计
- 旧版本不能脱离Web
- 新版本对整个框架进行了分层抽取,分成了核心模块和Web模块。单独引入核心模块就可以脱离Web环境
- 重量级
SpringSecurity的Hello项目
创建一个项目
第一步:创建一个SpringBoot项目。
第二步:引入需要的依赖。
<dependencies>
<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>
</dependencies>
第三步:创建TestController
package com.yyp.securitydemo1.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/hello")
public String hello(){
return "hello security";
}
}
运行这个项目
上面我们创建了一个非常简单的SpringBoot的项目,当我们运行的时候回发成上面呢?
首先我们疑惑地是。这个页面哪里来的,为什么回来到这个页面,我们访问的controller有没有访问到呢?这个我在接下来会告诉大家,现在我们来登录一下,SpringSecurity默认的用户名是user密码会在后台告诉我们。
登录之后,我们就访问到了我们的controller
SpringSecurity的本质
SpringSecurity的本质就是过滤器链
FilterSecurityInterceptor:是一个方法的权限过滤器,基本位于过滤链的最底层
ExceptionTranslationFilter:是一个异常过滤器,用来处理在认证授权过程中抛出的异常
UsernamePasswordAuthenticationFilter:对/login的POST请求做拦截,校验表单中的用户名,密码
过滤器是如何加载的?
1、使用SpringSecurity配置过滤器
2、DelegatingFilterProxy类中的doFilter会首先运行
3、在doFilter方法中delegateToUse = initDelegate(wac);调用initDelegate方法
4、Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class);在当前作用域获取对象名字为springSecurityFilterChain的,返回一个过滤器对象。
SpringSecurity设置登录的用户名和密码
1、用过配置文件
直接在application.yaml中配置就可以
2、通过配置类
package com.yyp.securitydemo1.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;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password = passwordEncoder.encode("123");
auth.inMemoryAuthentication().withUser("lucy").password(password).roles("admin");
}
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
}
3、自定义实现类设置
注意将配置类注释掉,删除配置文件中的配置
第一步:创建配置类,设置使用哪个userDetailsService实现类
package com.yyp.securitydemo1.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;
@Configuration
public class SecurityConfigTest 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对象有用户名密码和操作权限
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new User("mary",new BCryptPasswordEncoder().encode("123"),auths);
}
}
我们通过数据库查到用户的用户名密码和权限,通过User来进行认证。
SpringSecurity-Web权限方案(真正的数据库实现)
思路:整合一个框架MybatisPlus。
引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
创建数据库和数据库表
创建实体类
package com.yyp.securitydemo1.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
private Integer id;
private String username;
private String password;
}
整合MybatisPlus,创建接口,继承MybatisPlus接口
public interface UsersMapper extends BaseMapper<Users> {
}
在MyUserDetailsService调用mapper里面得方法查询数据库进行用户认证
package com.yyp.securitydemo1.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yyp.securitydemo1.entity.Users;
import com.yyp.securitydemo1.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 MyUserDetailsService implements UserDetailsService {
@Autowired
private UsersMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<Users> wrapper = new QueryWrapper();
wrapper.eq("username",username);
Users user = usersMapper.selectOne(wrapper);
if (user == null){
throw new UsernameNotFoundException("用户名不存在!");
}
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new User(user.getUsername(),new BCryptPasswordEncoder().encode(user.getPassword()),auths);
}
}