zoukankan      html  css  js  c++  java
  • spring boot + spring Security + redis token 思路爬坡

    spring boot + spring Security + redis + token 爬坡

    分为几个部分 spring boot 基本配置 controller接口部分  安全校验部分(包括session或者自定义token的形式) redis的token存放于取出  , 在数据库取用户信息

    spring boot 基本配置

    pom和启动类

    https://www.cnblogs.com/funkboy/p/12889708.html     pom的jar版本要一一对应,不要产生spring冲突

    application.yml 和 properties 配置

    https://www.cnblogs.com/luzhanshi/p/10597641.html  like this

    实现检验思路

    Security 部分

    两种思路,

    第一种

    一种是spring Security只负责校验 ,生成和存储token的部分放在controller里

    这种情况只需要

    WebSecurityConfigurer extends WebSecurityConfigurerAdapter 
    configure:
    http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // JWT Filter 校验部分
    在登录的接口配置权限
    @PreAuthorize("hasAuthority('ddd:list')")

     filter部分

    package com.lzw.security.filter;
    
    import com.alibaba.fastjson.JSON;
    import com.lzw.security.common.GenericResponse;
    import com.lzw.security.common.ServiceError;
    import com.lzw.security.entity.User;
    import com.lzw.security.service.SelfUserDetailsService;
    import com.lzw.security.util.*;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
    import org.springframework.stereotype.Component;
    import org.springframework.web.filter.OncePerRequestFilter;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Set;
    
    /**
     * @author: jamesluozhiwei 组2
     * @description: 确保在一次请求只通过一次filter,而不需要重复执行  被springboot security 主类 调用
     */
    @Component
    @Slf4j
    public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    
        @Value("${token.expirationMilliSeconds}")
        private long expirationMilliSeconds;
    
        @Autowired
        SelfUserDetailsService userDetailsService;
    
        @Autowired
        RedisUtil redisUtil;
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
           //?
            String authHeader = request.getHeader("Authorization");
            response.setCharacterEncoding("utf-8");
            if (null == authHeader || !authHeader.startsWith("Bearer ")){
                filterChain.doFilter(request,response);//token格式不正确
                return;
            }
            String authToken = authHeader.substring("Bearer ".length());
    
            String subject = JwtTokenUtil.parseToken(authToken);//获取在token中自定义的subject,用作用户标识,用来获取用户权限
    
            //获取redis中的token信息
    
            if (!redisUtil.hasKey(authToken)){
                //token 不存在 返回错误信息
                response.getWriter().write(JSON.toJSONString(GenericResponse.response(ServiceError.GLOBAL_ERR_NO_SIGN_IN)));
                return;
            }
    
            //获取缓存中的信息(根据自己的业务进行拓展)
            HashMap<String,Object> hashMap = (HashMap<String, Object>) redisUtil.hget(authToken);
            //从tokenInfo中取出用户信息   ********
            User user = new User();
            user.setId(Long.parseLong(hashMap.get("id").toString())).setAuthorities((Set<? extends GrantedAuthority>) hashMap.get("authorities"));
            if (null == hashMap){
                //用户信息不存在或转换错误,返回错误信息
                response.getWriter().write(JSON.toJSONString(GenericResponse.response(ServiceError.GLOBAL_ERR_NO_SIGN_IN)));
                return;
            }
            //更新token过期时间
            redisUtil.setKeyExpire(authToken,expirationMilliSeconds);
            //将信息交给security  *******
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user,null,user.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            filterChain.doFilter(request,response);
        }
    }

    第二种

    另一种全部托管于spring Security

     mian class
    WebSecurityConfigurer extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(customUserDetailsService) .passwordEncoder(passwordEncoder()); } 设置查询方法 customUserDetailsService: //数据库查信息实现 UserDetailsService @Component public class CustomUserDetailsService implements UserDetailsService passwordEncoder() @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    xxxxxxxxxxx
    return user;
    }
    把放入token到redis的任务赋给handler
    public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler

    在filter里

    先把token和用户权限存放到redis
    并且
    public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    ...
     @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    ...
     UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user,null,user.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            filterChain.doFilter(request,response);

     Redis token 部分

    在页面调用登录接口时校验 如果数据正确 生成一组redis数据 包含username 权限组 token 等 ,返回token串,接下来所有的请求就要带上这个token ,如果请求符合这个token所代表的用户就放行,如果不符合就会被token过滤,返回失败handler

    与前端交互

     做好与前端协调,可选全json的数据交换,也可用post body 传值 

    post 请求

    获取值 https://blog.csdn.net/qq_41665356/article/details/80234392

    可以用string vo形参和httprequest获取

    postman 介绍

    https://www.cnblogs.com/zhuxr/p/9009708.html

     附赠小提示

    controller接口部分

    @RestController/Controller  注入   @RequestMapping 等 获取请求与返回

       spring PreAuthorize 配置  https://blog.csdn.net/weixin_39220472/article/details/80873268  

        @RequestMapping("/info/{id}") 参数restful
        @PreAuthorize("hasRole('sys:config:info')") 权限校验
        public R info(@PathVariable("id") Long id){
            SysConfig config = sysConfigService.getById(id);
    
            return R.ok().put("config", config);
        }
    value:  指定请求的实际地址, 比如 /action/info之类。
    method:  指定请求的method类型, GET、POST、PUT、DELETE等
    consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
    produces:    指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
    params: 指定request中必须包含某些参数值是,才让该方法处理
    headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求

    R: 一个vo 

     

    spring security 爬坡

    主要类分析

    public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter

    Security主体类 功能实现基础

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    自定义安全校验 --> AuthenticationManagerBuilder
    用于创建AuthenticationManager的SecurityBuilder。允许轻松构建内存身份验证,LDAP身份验证,基于JDBC的身份验证,添加UserDetailsS​​ervice以及添加AuthenticationProvider。

    auth.userDetailsService(customUserDetailsService) customUserDetailsService 这是一个继承UserDetailsService 的Component 重写方法loadUserByUsername 在数据库里校验身份

    protected void configure(HttpSecurity http) {  过滤的主方法,核心
    antMatchers(urls[String 数组]) 放行的url 数组

    .sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 关闭session
    csrf()
    Adds CSRF support. This is activated by default when using WebSecurityConfigurerAdapter's default constructor. You can disable it using:
     @Configuration
     @EnableWebSecurity
     public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
    
            @Override
         protected void configure(HttpSecurity http) throws Exception {
             http
                 .csrf().disable()
                 ...;
         }
     }
     
    Returns:
    the CsrfConfigurer for further customizations
    Throws:
    java.lang.Exception


    ! 在所有filter 之前

    addFilterBefore
    public HttpSecurity addFilterBefore(javax.servlet.Filter filter,
                                        java.lang.Class<? extends javax.servlet.Filter> beforeFilter)
    Description copied from interface: HttpSecurityBuilder
    Allows adding a Filter before one of the known Filter classes. The known Filter instances are either a Filter listed in HttpSecurityBuilder.addFilter(Filter) or a Filter that has already been added using HttpSecurityBuilder.addFilterAfter(Filter, Class) or HttpSecurityBuilder.addFilterBefore(Filter, Class).
    Specified by:
    addFilterBefore in interface HttpSecurityBuilder<HttpSecurity>
    Parameters:
    filter - the Filter to register before the type beforeFilter
    beforeFilter - the Class of the known Filter.
    Returns:
    the HttpSecurity for further customizations
    这个是所有的访问都要过一下在这加过滤token的code

    @SneakyThrows
    lombok 甩出所有的错误
    @EnableWebSecurity
    https://blog.csdn.net/andy_zhang2007/article/details/90023901
    该注解其实起到了如下效果 :
    
    控制Spring Security是否使用调试模式(通过注解属性debug指定),缺省为false,表示缺省不使用调试模式;
    导入 WebSecurityConfiguration,用于配置Web安全过滤器FilterChainProxy;
    若干个WebSecurityConfigurerAdapter作用于一个WebSecurity生成一个最终使用的web安全过滤器FilterChainProxy
    如果是Servlet 环境,导入WebMvcSecurityConfiguration;
    如果是OAuth2环境,导入OAuth2ClientConfiguration;
    使用注解@EnableGlobalAuthentication启用全局认证机制
    ————————————————
    版权声明:本文为CSDN博主「安迪源文」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/andy_zhang2007/article/details/90023901

    关于 @EnableGlobalMethodSecurity 开启spring 

    https://www.cnblogs.com/520playboy/p/7286085.html

    @bean

    注入实例到spring 工厂中以便于@Autowired等获取

    没写完呢

  • 相关阅读:
    windows_MySQL安装详解
    nginx 基本安全优化
    pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.
    浏览器缓存
    JavaScript迭代
    js模块开发
    关于逻辑删除标识字段value的设定
    c#单例(Singleton)模式实现
    css兼容小问题
    IIS网站不能访问
  • 原文地址:https://www.cnblogs.com/funkboy/p/13553028.html
Copyright © 2011-2022 走看看