首页 > 编程语言 > 详细

spring boot + spring Security + redis + token 爬坡

时间:2020-12-20 15:01:18      阅读:21      评论:0      收藏:0      [点我收藏+]

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(); } 把放入token到redis的任务赋给handler public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Autowired private RedisTemplate redisTemplate; private ObjectMapper objectMapper = new ObjectMapper(); @SneakyThrows @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication){ String token; Long userId = 0l; if(authentication.getPrincipal() instanceof CustomUserDetailsUser){ // CustomUserDetailsUser userDetailsUser = (CustomUserDetailsUser) authentication.getPrincipal(); token = SecureUtil.md5(userDetailsUser.getUsername() + System.currentTimeMillis()); userId = userDetailsUser.getUserId(); }else { token = SecureUtil.md5(String.valueOf(System.currentTimeMillis())); } //redis放token redisTemplate.opsForValue().set(Constant.AUTHENTICATION_TOKEN + token,token,Constant.TOKEN_EXPIRE, TimeUnit.SECONDS); redisTemplate.opsForValue().set(token,userId,Constant.TOKEN_EXPIRE, TimeUnit.SECONDS); response.setCharacterEncoding(CharsetUtil.UTF_8); //网页头 response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); //登陆成功了加token到浏览器 ? PrintWriter printWriter = response.getWriter(); printWriter.append(objectMapper.writeValueAsString(R.ok().put(Constant.TOKEN,token))); }

在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);

 

 

 附赠小提示

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 

 

post 请求

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

可以用string vo形参和httprequest获取

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等获取

 

spring boot + spring Security + redis + token 爬坡

原文:https://www.cnblogs.com/funkboy/p/13553028.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!