SpringSecurity认证笔记

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,经济版 1GB 1个月
简介: SpringSecurity认证笔记

Spring Security 是 Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。本文为学习三更草堂B站视频做个笔记便于回顾。

引入依赖

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.0.0</version>
        </dependency>

SpringSecurity完整流程

1e0bd82c0c46980f8280220b83b2c37a.png

UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名密码后的登陆请求。入门案例的认证工作主要有它负责。


ExceptionTranslationFilter:处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException。


FilterSecurityInterceptor:负责权限校验的过滤器。


认证流程详解

0e910c1fa8ceec973cabb8c284fecac4.png

Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。


AuthenticationManager接口:定义了认证Authentication的方法


UserDetailsService接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。


UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。


自定义登录接口

调用ProviderManager的方法进行认证 如果认证通过生成jwt。把用户信息存入redis中,自定义UserDetailsService。在这个实现类中去查询数据库。

校验:

定义Jwt认证过滤器


获取token解析token获取其中的userid,从redis中获取用户信息存入SecurityContextHolder。

JWT,Redis工具类在之前的文章存有,这里省略。

SpringSecurity配置类

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Autowired
    Au au;
    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/alipay/pay").permitAll()
                .antMatchers("/alipay/notify").permitAll()
                .antMatchers("/user/login").permitAll()
                .antMatchers("/register").permitAll().anyRequest().authenticated();
        http.cors();//允许跨域
        http.exceptionHandling().authenticationEntryPoint(au);//配置认证失败处理器
            http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

登录接口

 @PostMapping("/user/login")
    public Map<String,Object> login1(@RequestBody User user){
        Map<String,Object> map=new HashMap<>();
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(user.getLoginname(),user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        if(authenticate==null){
            map.put("list","error");
        }
        else {
            LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
            Long id = loginUser.getUser().getId();
         String token = JwtUtil.generateToken(id);
//            redisUtil.set(String.valueOf(id), loginUser.getUser());
            map.put("list","success");
            map.put("token",token);
        }
       return map;
    }

LoginUser实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginUser implements UserDetails, Serializable {
    private User user;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }
    @Override
    public String getPassword() {
        return user.getPassword();
    }
    @Override
    public String getUsername() {
        return user.getLoginname();
    }
    @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接口

@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String loginname) throws UsernameNotFoundException {
        User user = userMapper.selectOneByLoginname(loginname);
        if(user==null){
            throw new RuntimeException("用户名或者密码错误");
        }
        return new LoginUser(user);
    }
}

设置拦截器,这里的代码做了变动,因为在原先的代码,登录之后token过期不退出登录然后重新登陆就会报异常错误。

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    RedisUtil redisUtil;
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String token = httpServletRequest.getHeader("token");
        if(!StringUtils.hasText(token)){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
        Long userId;
        try {
            DecodedJWT decodedJWT = JwtUtil.decodeToken(token);
            userId = decodedJWT.getClaim("userId").asLong();
        }catch (Exception e){
            e.printStackTrace();
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
//      User user =(User) redisUtil.get(String.valueOf(userId));
//        if(Objects.isNull(user)){
//            filterChain.doFilter(httpServletRequest,httpServletResponse);
//            return;
//        }
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(null,null,null);
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}

设置认证失败处理器

@Component
public class Au implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setStatus(200);
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().print("用户认证失败");
    }
}


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
10月前
|
安全 Java 数据安全/隐私保护
SpringSecurity 认证流程
通过了解SpringSecurity核心组件后,就可以进一步了解其认证的实现流程了。
68 0
|
11月前
|
存储 安全 前端开发
详解SpringSecurity认证(下)
详解SpringSecurity认证(下)
91 0
|
7月前
|
安全 Java API
盘点认证框架 : SpringSecurity 基础篇
SpringSecurity 应该是最常见的认证框架了 , 处于Spring体系中使他能快速地上手 , 这一篇开始作为入门级开篇作 , 来浅浅地讲一下SpringSecurity 的整体结构.
|
11月前
|
安全 前端开发 Java
详解SpringSecurity认证(上)
详解SpringSecurity认证(上)
112 0
|
11月前
|
安全 Java 数据安全/隐私保护
马老师手写第二版Spring Security OAuth2.0认证授权教程
先是给大家基本概念,然后是基于Session的认证方式,紧接着会带着大家去快速的上手Spring Security,然后回去给大家详解解释Spring Security应用、然后就是分布式系统认证方案以及OAuth2.0,最后是Spring Security实现分布式系统授权!
|
12月前
|
存储 安全 Java
二.SpringSecurity基础-简单登录实现
SpringSecurity基础-简单登录实现
|
12月前
|
存储 安全 Java
SpringSecurity基础-简单登录实现
1.SpringSecurity介绍 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
73 0
|
12月前
|
存储 Java 数据库
三.SpringSecurity基础-认证原理
SpringSecurity基础-认证原理
|
12月前
|
存储 Java 数据库
SpringSecurity基础-认证原理
SpringSecurity是基于Filter实现认证和授权,底层通过FilterChainProxy代理去调用各种Filter(Filter链),Filter通过调用AuthenticationManager完成认证 ,通过调用AccessDecisionManager完成授权,SpringSecurity中核心的过滤器链详细如下:
77 0
|
12月前
|
JSON 前端开发 数据格式
SpringSecurity基础-认证授权结果处理
在传统的应用中,认证成功后页面需要跳转到认证成功页面或者跳转到个人中心页,但是在前后端分离的项目通常是使用Ajax请求完成认证,这时候我们需要返回一个JSON结果告知前端认证结果,然后前端自行跳转页面。 要做到上述功能,我们需要自定义认证成功处理器实现AuthenticationSuccessHandler接口复写 onAuthenticationSuccess方法,该方法其中一个参数是Authentication ,他里面封装了认证信息,用户信息UserDetails等,我们需要在这个方法中使用Response写出json数据即可
96 0