SpringSecurity的简单入手

一、使用配置类

说明 本篇只是自己做的笔记 不懂就可以直接私信问

旧版

/**
 * spring security配置
 *
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//开启注解支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 认证失败处理类
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;

    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;

    /**
     * 跨域过滤器
     */
    @Autowired
    private CorsFilter corsFilter;

    /**
     * 解决 无法直接注入 AuthenticationManager
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {

        return new BCryptPasswordEncoder();
    }

    /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        //在这里关联数据库和security 见一、3两种配置方法
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
    
        httpSecurity
                // CSRF禁用,因为不使用session
                .csrf().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 验证码captchaImage 允许匿名访问
                .antMatchers("/login", "/captchaImage").anonymous()
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).permitAll()
                .antMatchers("/profile/**").permitAll()
                .antMatchers("/common/download**").permitAll()
                .antMatchers("/common/download/resource**").permitAll()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/*/api-docs").permitAll()
                .antMatchers("/druid/**").permitAll()
                .antMatchers("/flowable/**").permitAll()
                .antMatchers("/socket/**").permitAll()
                .antMatchers("/api/common/**").permitAll()
                .antMatchers("/api/contract/**").permitAll()
                .antMatchers("/api/project/**").permitAll()
                .antMatchers("/api/document/**").permitAll()
                .antMatchers("/api/purchase/**").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                .headers().frameOptions().disable();
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        // 添加CORS filter
        httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
        httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
    }

    /***
     * 核心过滤器配置方法
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }
}

针对常用方法可以看https://blog.csdn.net/qq_31960623/article/details/120829127

新版 此处省略 你记得自己补充完整

@EnableWebSecurity
@Configuration
public class SecurityConfig{
 @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
    //拦截设置
    @SneakyThrows
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) {
        return http.antMatcher("").build();
    }
    //静态资源
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {

        return web -> {
        };

    }
    //身份认证接口
    @SneakyThrows
    @Bean
    public AuthenticationProvider daoAuthenticationProvider()  {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService();
        daoAuthenticationProvider.setPasswordEncoder();
        return AuthenticationProvider;
    }
}

1、HttpSecurity

http.formLogin()//开启表单认证 
.loginPage("/toLoginPage")//自定义登录页面		前后端分离无需设置
.loginProcessingUrl("/login")// 登录处理Url   前后端分离无需设置
.usernameParameter("username")//修改表单名字	
.passwordParameter("password")//修改表单密码
.successForwardUrl("xx类")// 登录成功后跳转路径 (详情看4)AuthenticationSuccess自动注入后添加进去
.failureHandler("xx类") // 登录失败逻辑处理   (详情看4)
.and().authorizeRequests()//设置安全认证
.antMatchers("/toLoginPage").permitAll()//放行登录页面 
.antMatchers("/doLogin").anonymous()//允许未登录的用户进行访问(匿名访问)
.anyRequest().authenticated();//所有请求都需要登录认证才能访问; 
.and().rememberMe()//开启记住我功能 
.tokenValiditySeconds(1209600)// token失效时间默认2周 
.rememberMeParameter("remember-me")// 自定义表单name值 前端传值可以true yes 1 on 都行-->
.apply() //添加配置  继承AbstractHttpConfigurer实现configure(HttpSecurity builder)
.failureHandler(authenticationFailure) //登录失败("见6")
.and()//而且
.authenticationEntryPoint(authenticationEnryPoint)  //未登录是的逻辑处理(见8)
.accessDeniedHandler(accessDeny)    //权限不足的时候的逻辑处理(见9)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//关闭session
=========================
//允许跨域
http.cors();
    
===========安全
// 设置/use 
http.authorizeRequests().antMatchers("/user/**").hasRole("ADMIN"); 
// 设置/user/** 访问需要PRODUCT角色和IP地址为127.0.0.1 .hasAnyRole("PRODUCT,ADMIN") 
http.authorizeRequests().antMatchers("/product/**") .access("hasAnyRole('ADMIN,PRODUCT') 
and hasIpAddress('127.0.0.1')");                                          
// 设置自定义权限不足信息   
                                                            http.exceptionHandling().accessDeniedHandler(xxx类);//详情看三中的2、


 http..csrf().disable();// 关闭csrf防护
http.headers().frameOptions().sameOrigin();// 允许iframe加载页面 

2、WebSecurity

web.ignoring().antMatchers("/css/**", "/images/**", "/js/**", "/favicon.ico");//解决静态资源被拦截的问题

3、AuthenticationManagerBuilder

auth.userDetailsService(userService)// 使用自定义用户认证  userService是看下面二、
    .passwordEncoder(bCryptPasswordEncoder());//使用密码加密
========= 或者
auth.authenticationProvider(xx.class);//个人理解此处是可以将加密到方法里(见6)

4、BCryptPasswordEncoder

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

二、基于数据库实现认证功能

1、UserServiceImpl

实现UserDetailsService接口

@Service
public class UserServiceImpl implements UserService, UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据名字查询数据库这里只是模仿创建user

        User user = User.builder().username("张山").password("@@@@").build();
        if (user == null) {
            throw new UsernameNotFoundException(username);
        }
        // 先声明一个权限集合, 因为构造方法里面不能传入null
        Collection<? extends GrantedAuthority> authorities = Lists.newArrayList();
        //返回对象   默认true不传参的话都是true
        //authorities存::new SimpleGrantedAuthority("ROLE_" + 权限名字)
        org.springframework.security.core.userdetails.User userDetails = new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                "{noop}" + user.getPassword(),// {noop}表示不加密认。{bcrypt} 加密认证
                true, // 用户是否启用 true 代表启用
                true,// 用户是否过期 true 代表未过期
                true,// 用户凭据是否过期 true 代表未过
                true,// 用户是否锁定 true 代表未锁定
                authorities//权限集合
        );
        return userDetails;
    }
}

2、加密

bcrypt****加密后的字符串形如:

$2a 10 10 10wouq9P/HNgvYj2jKtUN8rOJJNRVCWvn1XoWy55N3sCkEHZPo3lyWq

其中$是分割符,无意义;2a是bcrypt加密版本号;10是const的值;而后的前22位是salt值;再

然后的字符串就是密码的密文了;这里的const值即生成salt的迭代次数,默认值是10,推荐值

12。

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        //加密
        String encode = bCryptPasswordEncoder.encode("123456");      
        //验证密码是否正确
        boolean matches = bCryptPasswordEncoder.matches("123456", encode);

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

3、获取用户

    //3种方式获取
        UserDetails userDetails = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        //----        
        @RequestMapping("/loginUser2")
        @ResponseBody
        public UserDetails getCurrentUser(Authentication authentication) {
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            return userDetails;
        }
        //----        
        @RequestMapping("/loginUser3")
        @ResponseBody 
        public UserDetails getCurrentUser(@AuthenticationPrincipal UserDetails userDetails){ 
            return userDetails; 
        }

4、登录成功和失败

登录成功

实现AuthenticationSuccessHandler接口,并重写onAnthenticationSuccesss()方法.

@Component
public class AuthenticationSuccess implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        //登录成功时返回给前端的数据
        ApiResult<Object> result = ApiResult.result(StatusEnum.SUCCESS);
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSON.toJSONString(result));
    }
}

登录失败

实现AuthenticationFailureHandler接口,并重写onAuthenticationFailure()方法;

package com.jasper.jyunpan.config.security;

import com.alibaba.fastjson.JSON;
import com.jasper.jyunpan.model.dto.ApiResult;
import com.jasper.jyunpan.model.dto.StatusEnum;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author hao
 * @date 2022/3/25 15:06
 */
//登录失败返回给前端消息
@Component
public class AuthenticationFailure implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
        ApiResult result = null;
        if(e instanceof UsernameNotFoundException){
            result = ApiResult.result(StatusEnum.USERNAME_ERROR);
        }else if(e instanceof BadCredentialsException){
            result = ApiResult.result(StatusEnum.PASSWORD_ERROR);
        }else {
            result = ApiResult.fail(e.getMessage());
        }
        //处理编码方式,防止中文乱码的情况
        response.setContentType("text/json;charset=utf-8");
        //返回给前台
        response.getWriter().write(JSON.toJSONString(result));
    }
}

5、退出登录

实现LogoutSuccessHandler

@Component
public class AuthenticationLogout implements LogoutSuccessHandler {

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        ApiResult<Object> result = ApiResult.result(StatusEnum.SUCCESS);
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSON.toJSONString(result));
    }
}

6、自定义加密判断

实现AuthenticationProvider

/**
 * @author hao
 * @date 2022/3/25 15:34
 */
@Component
public class SelfAuthenticationProvider implements AuthenticationProvider {
   
    //此处实现UserDetailsService的那个类
    @Autowired
    CustomUserDetailsService UserServiceImpl;

    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String account= authentication.getName();     //获取用户名
        String password= (String) authentication.getCredentials();  //获取密码
        UserDetails userDetails= customUserDetailsService.loadUserByUsername(account);
        boolean checkPassword= bCryptPasswordEncoder.matches(password,userDetails.getPassword());
        if(!checkPassword){
            throw new BadCredentialsException("密码不正确,请重新登录!");
        }
        return new UsernamePasswordAuthenticationToken(account,password,userDetails.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

7、验证码

request.getURI().getPath()获取路径// == login   进行code判断  在网关中判断

8、未登录

实现AuthenticationEntryPoint

@Component
public class AuthenticationEnryPoint implements org.springframework.security.web.AuthenticationEntryPoint {

    /**
     * 未登录时返回给前端数据
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        ApiResult<Object> result = ApiResult.result(StatusEnum.UNAUTHORIZED);
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSON.toJSONString(result));
    }
}

三、权限

1、表达式

结合一、1中使用

表达式说明
permitAll指定任何人都允许访问。
denyAll指定任何人都不允许访问
anonymous指定匿名用户允许访问。
rememberMe指定已记住的用户允许访问。
authenticated指定任何经过身份验证的用户都允许访问,不包含anonymous
fullyAuthenticated指定由经过身份验证的用户允许访问,不包含anonymous和rememberMe
hasRole(role)指定需要特定的角色的用户允许访问, 会自动在角色前面插入’ROLE_’
hasAnyRole([role1,role2])指定需要任意一个角色的用户允许访问, 会自动在角色前面插入’ROLE_’
hasAuthority(authority)色前面插入’ROLE_'指定需要特定的权限的用户允许访问
hasIpAddress(ip)指定需要特定的IP地址可以访问
hasAnyAuthority([authority,authority])指定需要任意一个权限的用户允许访问

2、权限不足调用

/**
 * 无权访问处理器
 * @author hao
 * @date 2022/3/25 15:20
 */
@Component
public class AccessDeny implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException {
        ApiResult<Object> result = ApiResult.result(StatusEnum.NO_PERMISSION);
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSON.toJSONString(result));
    }
}

3、自定义权限限制

/*** 自定义授权类 */ 
@Component 
public class MyAuthorizationService { 
    public boolean check(Authentication authentication, HttpServletRequest request) {
        User user = (User) authentication.getPrincipal(); 
        // 获取用户所有权限 
        Collection<GrantedAuthority> authorities = user.getAuthorities(); 
        // 获取用户名 
        String username = user.getUsername(); 
        // 如果用户名为admin,则不需要认证 
        if (username.equalsIgnoreCase("admin")) { 
            return true; 
        } else { 
            // 循环用户的权限, 判断是否有ROLE_ADMIN权限, 有返回true 
            for (GrantedAuthority authority : authorities) { 
                String role = authority.getAuthority(); 
                if ("ROLE_ADMIN".equals(role)) { 
                    return true; 
                } 
            } 
        }
        return false; 
    } 
}

配置HttpSecurity

//使用自定义Bean授权 
http.authorizeRequests().antMatchers("/user/**"). access("@myAuthorizationService.check(authentication,request)");

带有参数的

public boolean check(Authentication authentication, HttpServletRequest request, Integer id) { 
    if (id > 10) {
        return false;
    }
    return true; 
}

配置类 来自你设置你接口的参数{id} 比如 localhost:8080/user/delete/1

//使用自定义Bean授权,并携带路径参数 
http.authorizeRequests().antMatchers("/user/delete/{id}"). access("@myAuthorizationService.check(authentication,request,#id)");

4、注解实现权限控制

@PreAuthorize ,
@PostAuthorize ,
@PreFilter , 
@PostFilter

@ProAuthorize : 注解适合进入方法前的权限验证

@PreAuthorize("hasRole('ADMIN')")//需要ADMIN权限 

//任意权限都可以
@PreAuthorize("hasAnyAuthority('admin','dept:list')")
===========================================================
@RequestMapping("/update/{id}")
@PreAuthorize("#id<10")
//针对参数权限限定 id<10可以访问 
public String update(@PathVariable Integer id, Model model) { 
    User user = userService.getById(id); 
    model.addAttribute("user", user); 
    return "user_update"; 
}

@PostAuthorize: 在方法执行后再进行权限验证,适合验证带有返回值的权

限, Spring EL 提供返回对象能够在表达式语言中获取到返回对象的 returnObject(返回值user)

/** * 根据ID查询用户 ** @return */ 
@GetMapping("/{id}") 
@ResponseBody 
@PostAuthorize("returnObject.username== authentication.principal.username")
//判断查询用户信息是否是当前登录用户信息.否则没有 权限 
public User getById(@PathVariable Integer id) { 
    User user = userService.getById(id); 
    return user; 
}

@PreFilter: 可以用来对集合类型的参数进行过滤, 将不符合条件的元素剔除集合

@GetMapping("/delByIds") 
@PreFilter(filterTarget = "ids", value = "filterObject%2==0")
//剔除参数为 基数的值 
public String delByIds(@RequestParam(value = "id") List<Integer> ids) { 
    for (Integer id : ids) {
        System.out.println(id); 
    } return "redirect:/user/findAll"; 
}

@PostFilter: 可以用来对集合类型的返回值进行过滤, 将不符合条件的元素剔除集合

@RequestMapping("/findAllTOJson") 
@ResponseBody 
@PostFilter("filterObject.id%2==0")//剔除返回值ID为偶数的值 
public List<User> findAllTOJson() { 
    List<User> userList = userService.list(); 
    return userList; 
}

四、跨域

/**
 * 解决跨域问题
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                //允许任何域名
                .allowedOriginPatterns("*")
                //允许任何方法
                .allowedMethods("PUT", "DELETE", "GET", "POST", "OPTIONS")
                //允许任何头
                .allowedHeaders("*")
                //暴露头
                .exposedHeaders("access-control-allow-headers",
                        "access-control-allow-methods",
                        "access-control-allow-origin",
                        "access-control-max-age",
                        "X-Frame-Options")
                // 是否允许证书(cookies)
                .allowCredentials(true)
                .maxAge(3600);
    }
}

五、流程

登录

UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("账号","密码");
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//将用户存入上下文中
SecurityContextHolder.getContext().setAuthentication(authenticationToken);

退出登录

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
 AuthUser authUser = (AuthUser) authentication.getPrincipal();
   //清除上下文
SecurityContextHolder.clearContext();

实体类


@Data
@AllArgsConstructor  //全参构造
@NoArgsConstructor  //无参构造
public class AuthUser implements UserDetails {

    private User user;

//   自行加上就ok
    private Collection<? extends GrantedAuthority> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }
	//此处也要改
    @Override
    public String getPassword() {
        return user.getPassword();
    }
	//此处要改
    @Override
    public String getUsername() {
        return user.getUsername();
    }

    // 账户是否未过期
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    // 账户是否未被锁
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

加数据授权

/**
 * 要实现UserDetailsService接口,这个接口是security提供的
 */
@Service(value = "userDetailsService")
public class AuthUserDetailsServiceImpl implements UserDetailsService {

    private static final Logger logger = LoggerFactory.getLogger(AuthUserDetailsServiceImpl.class);

    @Autowired
    private TUserService userService;

    @Autowired
    private TRoleService roleService;

    /**
     * 通过账号查找用户、角色的信息
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            User user = 数据库查询用户;
        if (user == null) {
            //用户名不存在
            throw new ServicesException(RespBeanEnum.USER_ACCOUNT_NOT_EXIST);
        } else {
            List<String> roles = 根据用户id查询出用户权限名字;
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            for (String role : roles) {
                authorities.add(new SimpleGrantedAuthority(role));
            }
            return new AuthUser(user, authorities);
        }
    }
}

过滤器


@Component
public class MyOncePerRequestFilter extends OncePerRequestFilter {


    @Value("${jwt.tokenHeader}")
    private String header;

    @Autowired
    private RedisCache redisCache;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {

        // header的值是在yml文件中定义的 “Authorization”
        String token = request.getHeader(header);
        System.out.println("MyOncePerRequestFilter-token = " + token);
        if (!StrUtil.isEmpty(token)) {
            String username = null;
            try {
                Claims claims = JwtUtil.parseJWT(token);
                username = claims.getSubject();
            } catch (Exception e) {
                e.printStackTrace();
//                throw new ServicesException("非法Token,请重新登陆", RespBeanEnum.ERROR);
                WriteJSON(request,response,new RespBean(RespBeanEnum.ERROR,"非法Token,请重新登陆"));
                return;
            }
            String redisToken = redisCache.getCacheObject("Token_" + username);
            System.out.println("MyOncePerRequestFilter-redisToken = " + redisToken);
            if (StrUtil.isEmpty(redisToken)) {
                //token令牌验证失败
//                throw new ServicesException(RespBeanEnum.TOKEN_VALIDATE_FAILED);

                //输出JSON
                WriteJSON(request,response,new RespBean(RespBeanEnum.TOKEN_VALIDATE_FAILED));
                return;
            }

            //对比前端发送请求携带的的token是否与redis中存储的一致
            if (!Objects.isNull(redisToken) && redisToken.equals(token)) {
                AuthUser authUser = redisCache.getCacheObject("UserDetails_" + username);
                System.out.println("MyOncePerRequestFilter-authUser = " + authUser);
                if (Objects.isNull(authUser)) {
//                    throw new ServicesException(RespBeanEnum.USER_NOT_LOGIN);
                    WriteJSON(request,response,new RespBean(RespBeanEnum.USER_NOT_LOGIN));
                    return;
                }
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authUser, null, authUser.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
    private void WriteJSON(HttpServletRequest request,
                             HttpServletResponse response,
                             Object obj) throws IOException, ServletException {
        //这里很重要,否则页面获取不到正常的JSON数据集
        response.setContentType("application/json;charset=UTF-8");

        //跨域设置
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Method", "POST,GET");
        //输出JSON
        PrintWriter out = response.getWriter();
        out.write(JSON.toJSONString(obj));
        out.flush();
        out.close();
    }
}
//正常放行
//UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authUser, null, authUser.getAuthorities());
//                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//chain.doFilter(request, response);

//没有token
//return;就行

配置类

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyOncePerRequestFilter myOncePerRequestFilter;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //1、关闭csrf,关闭Session
        http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        //2、设置不需要认证的URL
        http
                .authorizeRequests()
                //允许未登录的用户进行访问
                .antMatchers("/doLogin").anonymous()
                //其余url都要认证才能访问
                .anyRequest().authenticated();

        //3、在UsernamePasswordAuthenticationFilter前添加认证过滤器
        http.addFilterBefore(myOncePerRequestFilter, UsernamePasswordAuthenticationFilter.class);

    }
}

jwt设置令牌

链接

别人git仓库地址

仓库地址
源码

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Security 是一个功能强大且灵活的框架,用于在 Java 应用程序中实现身份验证和授权。以下是一个简单的示例,演示了如何在 Spring Security 中进行基本配置和使用。 首先,在 pom.xml 文件中添加 Spring Security 的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 接下来,创建一个配置类来配置 Spring Security。可以创建一个类,并使用 `@EnableWebSecurity` 注解进行标记: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/public").permitAll() .anyRequest().authenticated() .and() .formLogin().permitAll() .and() .logout().permitAll(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password(passwordEncoder().encode("password")).roles("ADMIN") .and() .withUser("user").password(passwordEncoder().encode("password")).roles("USER"); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 上述配置类中,我们通过 `configure(HttpSecurity http)` 方法定义了 URL 的访问权限规则,并配置了登录和登出行为。通过 `configure(AuthenticationManagerBuilder auth)` 方法,我们在内存中定义了两个用户(admin 和 user)及其密码和角色。 最后,创建一个简单的控制器类来定义一些访问路径。可以使用 `@RestController` 注解来标记该类,并使用 `@RequestMapping` 注解来定义请求路径: ```java @RestController public class HelloController { @RequestMapping("/public") public String publicEndpoint() { return "Public endpoint"; } @RequestMapping("/private") public String privateEndpoint() { return "Private endpoint"; } } ``` 以上示例中,`/public` 路径是公开访问的,而 `/private` 路径需要进行身份验证才能访问。 这只是一个简单的示例,展示了 Spring Security 的基本用法。你可以根据自己的需求进行更复杂的配置和定制化。希望对你有所帮助!如果有更多问题,请继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张航柯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值