SpringSecurity

SpringSecurity

alt

默认拥有 /login接口和/logout接口

alt

设计 API 授权,或者调用第三方 API 时,经常会接触到: Authorization : Bearer Tokenxxxxxx

有没有疑惑为何不直接写成这样就得了: Authorization : Tokenxxxxxx

这是因为 W3C 的 HTTP 1.0 规范,
Authorization 的格式是 Authorization: <type> <authorization-parameters> Bearer 是授权的类型,
常见的授权类型还有:
– Basic 用于 http-basic 认证;
– Bearer 常见于 OAuth 和 JWT 授权;
– Digest MD5 哈希的 http-basic 认证 (已弃用)
– AWS4-HMAC-SHA256 AWS 授权
.......

spring security 的 配置类

  package com.example.demo.config;

import com.example.demo.filter.AccountVerifyFilter;
import com.example.demo.filter.CaptchaVerifyFilter;
import com.example.demo.filter.EncodeHandleFilter;
import com.example.demo.filter.JwtTokenVerifyFilter;
import com.example.demo.handler.*;
import com.example.demo.service.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
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.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.time.Duration;
import java.util.Arrays;

/**
 * @author : sheep669
 * @description : spring security 的 配置类
 * @created at 2022/7/11 16:50
 */
@Configuration
public class SecurityConfig {

    /**
     * 注入验证码验证过滤器
     *
     * @author sheep669
     * @created at 2022/7/18 14:50
     */
    @Autowired
    private CaptchaVerifyFilter captchaVerifyFilter;

    /**
     * Token验证是否存在过滤器
     *
     * @author sheep669
     * @created at 2022/7/18 14:56
     */
    @Autowired
    private JwtTokenVerifyFilter jwtTokenVerifyFilter;

    /**
     * 配置加密方式, 替换默认的 PasswordEncoder 采用 spring security 提供的 BCryptPasswordEncoder
     *
     * @return PasswordEncoder
     * @author sheep669
     * @created at 2022/7/17 18:34
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
        // return NoOpPasswordEncoder.getInstance();  让密码明文存储也可登录 过时了
    }

    /**
     * 注入UserDetailsService返回自定义的实现类
     *
     * @return UserDetailsService
     * @author sheep669
     * @created at 2022/7/17 21:18
     */
    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailServiceImpl();
    }

    /**
     * 登录成功处理器
     *
     * @author sheep669
     * @created at 2022/7/17 18:55
     */

    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    /**
     * 登录失败处理器
     *
     * @author sheep669
     * @created at 2022/7/17 18:55
     */

    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    /**
     * 用户未登录处理器
     *
     * @author sheep669
     * @created at 2022/7/17 18:55
     */

    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;

    /**
     * 权限不足处理器
     *
     * @author sheep669
     * @created at 2022/7/17 18:55
     */

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    /**
     * 注销处理器
     *
     * @author sheep669
     * @created at 2022/7/17 18:55
     */

    @Autowired
    private MyLogoutHandler myLogoutHandler;

    /**
     * 注销成功处理器
     *
     * @author sheep669
     * @created at 2022/7/17 18:55
     */

    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;


    @Autowired
    private AccountVerifyFilter accountVerifyFilter;


    @Autowired
    private EncodeHandleFilter encodeHandleFilter;


    /**
     * 配置过滤拦截
     * anonymous() 允许匿名用户访问,不允许已登入用户访问
     * permitAll() 不管登入,不登入 都能访问
     *
     * @param http 请求配置
     * @return SecurityFilterChain
     * @author sheep669
     * @created at 2022/7/17 18:35
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/captcha").anonymous()
                .antMatchers("/get_menu_data").anonymous()
                .anyRequest().authenticated()
                .and().addFilterBefore(captchaVerifyFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(jwtTokenVerifyFilter, CaptchaVerifyFilter.class)
                .addFilterBefore(accountVerifyFilter, JwtTokenVerifyFilter.class)
                .addFilterBefore(encodeHandleFilter, AccountVerifyFilter.class)
                .formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .successHandler(myAuthenticationSuccessHandler)
                .failureHandler(myAuthenticationFailureHandler)
                .and().exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint)
                .accessDeniedHandler(myAccessDeniedHandler)
                .and().logout().permitAll()
                .addLogoutHandler(myLogoutHandler)
                .logoutSuccessHandler(myLogoutSuccessHandler)
                .deleteCookies("JSESSIONID")
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().csrf().disable()
                .cors().configurationSource(corsConfigurationSource());
        return http.build();
    }


    /**
     * 注入授权提供者, 设置授权实现类和密码校验
     *
     * @return DaoAuthenticationProvider
     * @author sheep669
     * @created at 2022/7/17 21:19
     */
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService());
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }

    /**
     * 配置跨域
     *
     * @return CorsConfigurationSource
     * @author sheep669
     * @created at 2022/7/22 14:01
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        // 新建一个跨域配置
        CorsConfiguration configuration = new CorsConfiguration();
        // 允许跨域访问的域名
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:8081", "http://localhost:8082"));
        // 允许访问的方法名
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "DELETE", "PUT"));
        // 允许请求携带验证信息
        configuration.setAllowCredentials(true);
        // 跨域允许时间 3秒
        configuration.setMaxAge(Duration.ofMillis(3000));
        // 允许服务端访问客户端的请求头
        configuration.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        // 允许跨域访问的请求 所有请求 /**
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

核心实现

 package com.example.demo.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.pojo.User;
import com.example.demo.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
* @author : sheep669
* @description : TODO
* @created at 2022/7/17 15:26
*/
public class UserDetailServiceImpl implements UserDetailsService {
   @Autowired
   private UserMapper userMapper;
   @Autowired
   private RedisUtil redisUtil;

   @Override
   public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
       LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
       queryWrapper.eq(User::getUsername, username);
       User user = userMapper.selectOne(queryWrapper);
       if (ObjectUtil.isNull(user)) {
           throw new UsernameNotFoundException("用户不存在!");
       } else {
           Map<String, Object> map = new HashMap<>(16);
           map.put("userInfo", user.getUsername());
           String token = JWTUtil.createToken(map, user.getUsername().getBytes());
           redisUtil.setValueByKey("token", token);
           redisUtil.setValueByKey("key", user.getUsername());
           redisUtil.setValueByKey("role", user.getRole());
       }
       ArrayList<GrantedAuthority> authorities = new ArrayList<>();
       SimpleGrantedAuthority role = new SimpleGrantedAuthority(user.getRole());
       authorities.add(role);
       return new org.springframework.security.core.userdetails.User(user.getUsername(),
               user.getPassword(), authorities);
   }
}

全部评论

相关推荐

程序员小白条:这比例牛逼,750:1
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务