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配置过滤器DelegatingFilterProxydoFilterpublic 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")
