stater

//依赖导入<dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-security</artifactId></dependency>

写一个controller类测试

@RestController@RequestMapping("/test")public class TestController {    @GetMapping("hello")    public String hello(){        return "hello";    }}

运行胜利之后会提供一个明码

用户名默认为 userUsing generated security password: 9afa3ef4-035c-44bc-8dd2-c9e0e8121638

过滤链

SpringSecurity实质就时一个过滤链

在服务申请时创立,每个过滤器要放行能力去下一步

FilterSecurityInterceptor 办法级的权限过滤器,根本谓语过滤链的底部

doFilter 才是真正的过滤办法public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        this.invoke(new FilterInvocation(request, response, chain));    }invoke 具体执行的办法    InterceptorStatusToken token = super.beforeInvocation(filterInvocation);//过滤器之前必须被放行才会继续执行上面的方面

ExceptionTranslationFilter 异样过滤器 用来解决认证受权过程中抛出的异样

doFilter中会判断你的异样 而后进行解决

UsernamePasswordAuthenticationFilter 对/login的POST申请做拦挡,校验表单中的用户名,明码。

 private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/login", "POST");public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {        if (this.postOnly && !request.getMethod().equals("POST")) {            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());        } else {            String username = this.obtainUsername(request);            username = username != null ? username : "";            username = username.trim();            String password = this.obtainPassword(request);            password = password != null ? password : "";            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);            this.setDetails(request, authRequest);            return this.getAuthenticationManager().authenticate(authRequest);        }    }

过滤器加载过程

springboot会对springsecurity进行一个自动化的配置计划,所以咱们引入依赖就能够不必额定配置。

1、应用SpringSecurity配置过滤器DelegatingFilterProxy

doFilterpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {    Filter delegateToUse = this.delegate;    if (delegateToUse == null) {        synchronized(this.delegateMonitor) {            delegateToUse = this.delegate;            if (delegateToUse == null) {                WebApplicationContext wac = this.findWebApplicationContext();                if (wac == null) {                    throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");                }                delegateToUse = this.initDelegate(wac);            }            this.delegate = delegateToUse;        }    }    this.invokeDelegate(delegateToUse, request, response, filterChain);}initDelegateprotected Filter initDelegate(WebApplicationContext wac) throws ServletException {        String targetBeanName = this.getTargetBeanName();        Assert.state(targetBeanName != null, "No target bean name set");        Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class);        if (this.isTargetFilterLifecycle()) {            delegate.init(this.getFilterConfig());        }        return delegate;    }

doFilter中会调用初始化办法initDelegate,他会失去一个过滤器的名字targetBeanName 会失去FilterChainProxy这个内置过滤器

//过滤链中的所以过滤器都放过来List<Filter> filters = this.getFilters((HttpServletRequest)firewallRequest);private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest)request);        HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse)response);        List<Filter> filters = this.getFilters((HttpServletRequest)firewallRequest);        if (filters != null && filters.size() != 0) {            if (logger.isDebugEnabled()) {                logger.debug(LogMessage.of(() -> {                    return "Securing " + requestLine(firewallRequest);                }));            }            FilterChainProxy.VirtualFilterChain virtualFilterChain = new FilterChainProxy.VirtualFilterChain(firewallRequest, chain, filters);            virtualFilterChain.doFilter(firewallRequest, firewallResponse);        } else {            if (logger.isTraceEnabled()) {                logger.trace(LogMessage.of(() -> {                    return "No security for " + requestLine(firewallRequest);                }));            }            firewallRequest.reset();            chain.doFilter(firewallRequest, firewallResponse);        }    }        private List<Filter> getFilters(HttpServletRequest request) {        int count = 0;        Iterator var3 = this.filterChains.iterator();        SecurityFilterChain chain;        do {            if (!var3.hasNext()) {                return null;            }            chain = (SecurityFilterChain)var3.next();            if (logger.isTraceEnabled()) {                ++count;                logger.trace(LogMessage.format("Trying to match request against %s (%d/%d)", chain, count, this.filterChains.size()));            }        } while(!chain.matches(request));        return chain.getFilters();    }

FilterChainProxy里就时把所以的过滤器加载到了过滤链中

两个重要接口

用户名时固定的user,明码是主动生成的,然而咱们必定是是要改的。

1.创立一个类继承UsernamePasswordAuthenticationFilter ,而后从新外面的三个办法,attemptAuthentication,successfulAuthentication,unsuccessfulAuthentication,

2.创立类实现UserDetailsService 接口,编写查询数据库的过程,返回一个User对象,这个user是平安框架的对象,不是本人写的。

UserDetailsService

这个接口就是写去数据库查货色的过程。

PasswordEcoder

数据加密接口,用于返回的User对象外面明码的加密

设置登录的用户名和明码

第一种、通过配置文件配置

spring:  security:    user:      name: "shuaikb"      password: "shuaikb"

第二种、通过配置类

@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {    @Bean    PasswordEncoder passwordEncoder(){        return new BCryptPasswordEncoder();    }    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();        String password = bCryptPasswordEncoder.encode("123");        auth.inMemoryAuthentication().withUser("test").password(password).roles("admin");    }}//留神要去掉super.configure(auth);

第三种、自定义编写实现类

如果你在配置文件和配置类都没有配置用户和明码,零碎就会去找UserDetailsService 这个接口

1.创立一个类继承UsernamePasswordAuthenticationFilter ,而后从新外面的三个办法,attemptAuthentication,successfulAuthentication,unsuccessfulAuthentication,

2.创立类实现UserDetailsService 接口,编写查询数据库的过程,返回一个User对象,这个user是平安框架的对象,不是本人写的

@Configurationpublic class SecurityConfig3 extends WebSecurityConfigurerAdapter {    @Autowired    private UserDetailsService userDetailsService;    @Bean    PasswordEncoder passwordEncoder(){        return new BCryptPasswordEncoder();    }    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());    }}
@Service("userDetailsService")public class MyUserDetailsService implements UserDetailsService {    @Override    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {        //权限汇合        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");        return new User("shuaikb",new BCryptPasswordEncoder().encode("123"),auths);    }}

整合数据库

<dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId></dependency><dependency>            <groupId>com.baomidou</groupId>            <artifactId>mybatis-plus-boot-starter</artifactId>            <version>3.4.3.1</version></dependency>

实体类

/** * @Author Shuaikb * @create 2021/8/23 20:54 */@Datapublic class Users {    private String id;    private String usernma;    private String password;}

mapper接口

/** * @Author Shuaikb * @create 2021/8/23 20:56 */public interface UserMapper extends BaseMapper<Users>{}

在service中去注入接口

@Autowired    private UserMapper userMapper;

具体判断代码

/** * @Author Shuaikb * @create 2021/8/22 23:43 */@Service("userDetailsService")public class MyUserDetailsService implements UserDetailsService {    @Autowired    private UserMapper userMapper;    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        //依据用户名去查用户        QueryWrapper<Users> queryWrapper = new QueryWrapper();        queryWrapper.eq("username",username);        Users users = userMapper.selectOne(queryWrapper);        if (users ==null){            throw new UsernameNotFoundException("用户名不存在!");        }        //权限汇合        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");        return new User(users.getUsernma(),new BCryptPasswordEncoder().encode(users.getPassword()),auths);    }}留神有mapper 就要在启动类加注解@MapperScan("com.example.springsecurity.mapper")