ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

记录SpringSecurity jwt问题

2021-09-23 09:02:22  阅读:135  来源: 互联网

标签:登录 记录 jwt 用户 SpringSecurity token https 权限


认证、授权、鉴权和权限控制


0.jwt 加签->验签 加签参数中包含:头部()负载(用户名,创建时间)验签:客户端传值与服务端算一致,别人篡改什么?用户名? 验签成功标识?失败提示什么?@篡改 用户名。1.token 错误,根据token 解析荷载是会报错,其实这里应该把异常抛出,token错误!
(业务:实际报异常:暂未登录或token已经过期,因为取了用户信息,取不到报错。不取用户不会报错,即便token错误)
 验签:就是根据token 反解jwt,无token或token被篡改,回报异常,说明验签失败!
 /**
     * 从token中获取JWT中的负载
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            LOGGER.info("JWT格式验证失败:{}", token, e);
        }
        return claims;
    }
    
1.注册后,用户信息怎么进入security的? @注册后没有存用户信息,是登录时,根据用户名查询数据库,然后存security。
2.权限怎么进去的   SecurityConfig configure 在这里从数据库查询权限,还有用户信息保存了,保存到哪里了?->AdminUserDetails 包含用户信息,权限信息,并提供对外接口
2.1 用户权限信息包含两部分 1.角色权限表 2.用户权限表,用户权限表数据怎么进去的(暂时业务没有用到)? @登录时,查数据库表,取权限赋值??不是登录时还是直接取UserDetailsService!!!。总结:登录赋值,调接口取值
3.sysUser 用户类 联系 @同一个
4.jwt 生成token原理
普通token只有过期时间与用户信息,而且会被伪造,jwt包含签名,不会被伪造。更像是一个签名
5.用户登录成功后,除了token,还有菜单权限数据,还有一个权限列表,这是个啥,权限值吗,有什么?鉴权吗? @前者只有菜单,后者包含所有,不只是权限,完整权限数据。应该不是控制权限,是控制数据是否展示。控制权限通过security注解
   Map<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", tokenHead);
        tokenMap.put("authorities", SecurityUtils.getAuthentication().getAuthorities()); @包含所有权限
        tokenMap.put("menuList", sysUserService.getMenuPermissionList(SecurityUtils.getUser().getId())); @只有菜单,没有按钮
    tokenMap.put("uid", SecurityUtils.getUser().getId());
    
    
6.根据用户名,获取用户信息密码,权限原理,@ 是登录成功后,缓存了!!! 用户名哪里来:根据token获取,jwt中获取,因为登录生产jwt时,存入了用户名。
7.jwt 自定义鉴权过滤器 做什么 1.用户名是否正确 security中获取与token中是否一直,token中是当前登录人,为什么? @防止A登录成功,拿B的token取调接口,扩大权限,显然只判断有效期不行,2.token是否过期 
8.UserDetailsService 根据用户名取用户信息,调用场景 登录时 1.登录取密码校验 2.jwt过滤器 验证用户名,token,最终从缓存中获取。但是入口在AdminUserDetails,说明在某时候数据进入了缓存 EhCache,进程内缓存,不支持分布式  @关于用户信息登录时,查库存security,其他接口直接取。
9.ums_admin_permission_relation 用户权限表中type=1含义 数据入口在->给用户分配+-权限,含义? @ 应该是增加删除权限,每次都是权限全量,与用户角色权限中权限比较,多:标记为+,少:标记为-,记的意义应该是保存记录
10.SecurityContext 取权限 赋值权限,但是权限值也是从UserDetails中获取,??此处哪里给?何时给?看上面:第8条
11.解决用户登录查库问题
首先,登录时是要查库,取用户与权限,只不过后面调接口时不必再查询数据库。
方式1.实现接口:UserDetailsService,重写方法,查询库把用户及权限信息写入,UserDetail接口。
方式2.重写配置类SecurityConfig 中 抽象类WebSecurityConfigurerAdapter userDetailsService方法
12.用户登录流程

虽然jwt配置了过滤登录请求,但是还是会走jwt过滤器(没有token 不会走jwt 认证及鉴权),然后到登录接口,根据用户名无法获得用户信息,说明用户名错误,抛出用户名密码错误。
如果密码错误,取到用户信息后,再比较密码,不正确抛出。那问题来了,为什么能获取用户信息???注册时缓存吗?@@@@查询数据库的!!每次都查询吗?应该是,之前有人说,不要每次查看?? @@@登录时,要查,调接口不再需要
13.权限来源于哪?UsernamePasswordAuthenticationToken 赋值过两次权限,都是从数据库查询用户权限,然后给到token。场景:1.登录 2.jwt过滤器(调用非登录接口时)。应该没有缓存,都是实时取表  @ 查库只有登录时,jwt过滤器也是取登录时赋值。jwt过滤器赋值权限,应该是注解鉴权时,跟这里比较。登录时,给了权限,为什么这里还要给??
   if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    LOGGER.info("authenticated user:{}", username);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
                
登录成功后,把信息赋值UserDetail接口(重写),后面调用其他接口,可以直接获取用户名。
正常的应该只需要登录时查询数据库,取出权限,后面调接口从缓存中获取,这里就涉及一个缓存刷新问题??? @@@应该是这样。

14.当未登录或者token失效,(无token或错误,无法根据token反解jwt,报异常,到下一个过滤链,进入自定义异常)访问接口时,自定义的返回结果  RestAuthenticationEntryPoint 调用接口未带token,来这里,{
  "code": 401,
  "data": "Full authentication is required to access this resource",
  "msg": "暂未登录或token已经过期"
}

15.访问接口时,可获取当前用户所有权限,具体怎么校验有没有权限,登录后,会返回菜单和权限,这时候前端会处理,没有就看不到菜单或者按钮。但是通过接口怎么拦截?@通过security注解,@PreAuthorize 在每一个接口上加权限。

    @PreAuthorize("hasAuthority('product')")
    @GetMapping("myRoom")
    @ApiOperation("我的直播间")
    public BaseResult<ResTextLiveProgramVo> myChatRoom() {
    return textLiveProgrammeService.myChatRoom();
    }

16.自定义:登录失败处理器,两种方式
@Component
//public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
public class RestAuthenticationEntryPoint implements AuthenticationFailureHandler {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println(JSON.toJSONString(BaseResult.unauthorized(authException.getMessage())));
        response.getWriter().flush();
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                    AuthenticationException e) throws IOException, ServletException {
        
    }
}

实际代码中并没有采用以上任意一种,而是在登录时,捕获了用户或密码错误异常,统一返回报错。

16.验证权限
无权限报错: 不允许访问
在接口添加权限限制 @PreAuthorize("hasAuthority('product') 
问题
1.没走自定义无权限,直接报:不允许访问
2.原理是什么,异常从哪抛出的
3.不手动添加权限限制,直接调接口,怎么实现鉴权 @ 每一个接口都是手动给权限

17.登出 
jwt 在有效期一直可用,无失效逻辑。
token:之前都是存在redis有失效机制。
需要做两件事
1.前端删除token
2.自定义登录处理器,并在security中配置,把请求头token设置为空。
登出过滤器
@Component
public class JwtLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException {
    if (Objects.nonNull(authentication)) {
        new SecurityContextLogoutHandler().logout(request, response, authentication);
    }
    response.setContentType("application/json;charset=UTF-8");
    ServletOutputStream outputStream = response.getOutputStream();
    response.setHeader("Authorization", "");
    BaseResult result = BaseResult.success("");
    outputStream.write(JSON.toJSONString(result).getBytes("UTF-8"));
    outputStream.flush();
    outputStream.close();
    }
}


18 SecurityConfig jwt直接关联
在security配置类中加 入jwt过滤器
1.创建实例
    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
        return new JwtAuthenticationTokenFilter();
    }
2.添加JWT filter
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);

19.jwt 存在问题
https://blog.csdn.net/hanxiaotongtong/article/details/103347063

20.token刷新
1.接口请求请求头带 token, Authorization:token
2.刷新token,只是在jwt生产token中,更新了创建时间

21.jwt作用 
1.认证 根据判断用户名,密码  jwt加签存了用户信息,验签验证身份
2.鉴权,权限不足 @主要由security完成,只是利用了jwt过滤器

22.spring Security 如何保存权限信息

UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
        null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);

涉及到上下文
public interface SecurityContext extends Serializable {
    Authentication getAuthentication();

    void setAuthentication(Authentication var1);
}

  SecurityContextHolder.getContext().setAuthentication(authentication);
  把权限信息给到给到上下问Context,两个地方,登录时,jwt验证后。登录后,已经把用户权限给context,为什么调接口还要赋值
  
  if (username != null && SecurityContextHolder.getContext().getAuthentication() == null),因为jwt判断为null才赋值,为什么为空
 
23.每次登录成功后,把用户及权限信息,保存到上下文,怎么实现用户隔离 

参考文档:
http://www.cocoachina.com/articles/42621
https://zhengkai.blog.csdn.net/article/details/96290686

赋值权限
AdminUserDetails(自定义认证主体,包含用户信息及权限信息类。认证:及校验密码,成功后,设置创建一个实现了 Authentication接口的对象,给上下文)-> UserDetails -> UsernamePasswordAuthenticationToken ->Authentication->SecurityContext->-ThreadLocal(又保存到httpSession,取的时候从这里)-@> SecurityContextHolder


SecurityContextHolder 是如何存储 SecurityContext 的。 ThreadLocalSecurityContextHolderStrategy 怎么存储到ThreadLocal
https://www.it610.com/article/1281109153997144064.htm
https://www.bbsmax.com/A/gVdnpGr1JW/
https://blog.csdn.net/liuyanglglg/article/details/104742799
https://blog.csdn.net/weixin_34366546/article/details/87994814?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-0.no_search_link&spm=1001.2101.3001.4242

【FilterChain】【HttpSession】【SecurityContextPersistenceFilter】
SecurityContextPersistenceFilter:
该Filter的作用主要是创建一个空的SecurityContext(如果session中没有SecurityContext实例),然后持久化到session中


HttpSessionSecurityContextRepository 
context 与httpsessin 绑定,为什么存在httpSession ,为什么也要保存到ThreadLocal
https://cloud.tencent.com/developer/article/1361030

https://blog.didispace.com/xjf-spring-security-4/ 比较全的源码分析
https://blog.didispace.com/xjf-spring-security-3/
SecurityContextPersistenceFilter 两个主要职责:请求来临时,创建SecurityContext安全上下文信息,请求结束时清空
请求来临时 指调用接口吗,请求结束接口执行完成吗?创建context是不是应该登录时创建。

https://www.bbsmax.com/A/gVdnpGr1JW/
https://www.it610.com/article/1281109153997144064.htm
https://zhengkai.blog.csdn.net/article/details/96290686
http://www.cocoachina.com/articles/42621
https://www.shuzhiduo.com/A/QW5YV87Gdm/
https://www.cnblogs.com/felordcn/p/12142491.html
https://blog.csdn.net/andy_zhang2007/article/details/91955225
https://my.oschina.net/u/2518341/blog/1982933
https://blog.csdn.net/qq_35067322/article/details/103209951
https://www.cnblogs.com/longfurcat/p/10293819.html
https://cloud.tencent.com/developer/article/1361030
https://blog.csdn.net/liuyanglglg/article/details/104742799
https://blog.csdn.net/weixin_34366546/article/details/87994814?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-0.no_search_link&spm=1001.2101.3001.4242
https://blog.csdn.net/fengyilin_henu/article/details/84916822
https://www.cnblogs.com/longfurcat/p/10574734.html


1.使用security 依赖,配置(方法级别)


jwt:
  tokenHeader: Authorization
  secret: mySecret
  # 60*60*24
  expiration: 604800  s /60/60 168  7天有效期
  tokenHead: Bearer
  
  

UserDetails:构建Authentication对象必须的信息,可以自定义,可能需要访问DB得到

SpringSecurity JWT
认证、授权、鉴权和权限控制


1.JWT作用:身份认证(token生成与校验)
生成与校验场景:生成:用户登录;校验:用户进行操作时,走JWT过滤器,从请求头中获取token,根据token反解JWT中的负载。
成功失败标志:从token中反解JWT中的负载时,如果异常,说明认证失败,无异常则认证成功

2.SpringSecurity:授权,鉴权
授权:创建用户选择权限及管理员分配权限,需要权限控制的方法上加注解:@PreAuthorize("hasAuthority('sys:role:update')")
SpringSecurity如何管理权限:接口请求走JWT过滤器,实时查数据库取用户基本信息与权限信息。
存在哪里:
怎么获取:
https://blog.csdn.net/u012702547/article/details/89629415
https://blog.csdn.net/weixin_39915815/article/details/111038973?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.nolandingword2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.nolandingword2

标签:登录,记录,jwt,用户,SpringSecurity,token,https,权限
来源: https://blog.csdn.net/C18298182575/article/details/120427660

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有