Spring Security安全登录的调用过程以及获取权限的调用过程

这篇具有很好参考价值的文章主要介绍了Spring Security安全登录的调用过程以及获取权限的调用过程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.第一次登录时候调用/user/login整个流程分析

Spring Security安全登录的调用过程以及获取权限的调用过程,spring安全代码笔记,spring,安全,java

(0)权限授理

首先调用SecurityConfig.java中的config函数将jwtAuthenticationTokenFilter过滤器放在UsernamePasswordAuthenticationFilter之前

@Override
protected void configure(HttpSecurity http) throws Exception{
    ......    
    http.addFilterBefore(jwtAuthenticationTokenFilter,UsernamePasswordAuthenticationFilter.class);
}

(1)首先运行JwtAuthenticationTokenFilter extends OncePerRequestFilter中的doFilterInternal函数

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        //1.获取token
        String token = httpServletRequest.getHeader("token");
        if(!StringUtils.hasText(token))
        {
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            //这里可以放行的原因在于后面还有FilterSecurityInterceptor等其他过滤器,
            //如果没有认证后面还会被拦截下来
            return;
            //这里如果没有return,响应回来之后还会调用后面的代码
        }

这里由于没有获取到token,因此调用!StringUtils.hasText(token),这里使用

filterChain.doFilter(httpServletRequest,httpServletResponse);

继续运行其他拦截器,然后返回

(2)接下来运行LoginServiceImpl.java中的login函数

public class LoginServiceImpl implements LoginService{
    ......
    public ResponseResult login(@RequestBody User user){
         UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
         Authentication authentication = authenticationManager.authenticate(authenticationToken);   
         ...... 
    } 
}

这里先根据UsernamePasswordAuthenticationToken放入user的name和password创建authenticationToken类

UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());

接下来调用authenticate函数认证,这里authenticate函数会调用UserDetailsService的实现类UserDetailsServiceImpl函数中的loadUserByUsername进行读取数据库

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //这里的UserDetails是一个接口,因此需要写一个对应的实现类
        //查询用户信息
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName,username);
        User user = userMapper.selectOne(queryWrapper);
        //如果没有查询到用户,就抛出异常
        if(Objects.isNull(user))
        {
            throw new RuntimeException("用户名或者密码错误!");
        }
        //因为在UsernamePasswordAuthenticationFilter之后
        //会调用一个ExceptionTranslationFilter,所以只要出现
        //异常都会被捕获到

        //TODO 查询对应的权限信息
        List<String> list = new ArrayList<>(Arrays.asList("test","admin"));
        //封装成UserDetails返回,标注类AllArgsConstructor,因此可以直接传入
        return new LoginUser(user,list);
    }

这里的UserDetailsService的调用有点像空中楼阁一样,原因在于它是在authenticationManager.authenticate(…)这个函数中默默的调用,因此出现的并不明显

(3)UserDetails实现类LoginUser的构造

这里创造新的类LoginUser并且传入user和list两大参数,进入LoginUser的构造函数和授权函数进行查看

public class LoginUser implements UserDetails {

    private User user;

    private List<String> permissions;

    public LoginUser(User user,List<String> permissions)
    {
        this.user = user;
        this.permissions = permissions;
    }

    //redis默认不会将List<SimpleGrantedAuthority> authorities序列化,
    //因为会报异常,所以我们不需要把authorities这个集合存入到redis之中
    @JSONField(serialize = false)
    private List<SimpleGrantedAuthority> authorities;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if(authorities != null)
        {
            return authorities;
        }
        authorities = permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
        //SimpleGrantedAuthority::new使用流的构造器,最后Collectors.toList()将结果转为list类型
        return authorities;
    }
    ......
}

这里的通过

authorities = permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());

将permissions中的两个参数"test"、"admin"分别构造SimpleGrantedAuthority类,并且放入Collectors之中,最终返回构造的Collectors权限信息,取出来的UsernamePasswordAuthenticationToken和Authentication类分别为

authentication = UsernamePasswordAuthenticationToken [Principal=LoginUser(user=User(id=111110, userName=xiaomazai, nickName=xiaomazai, password=$2a$10$VDFx9Khqpo4FAkx/NZLL3uZO0PcBZekL3AU5JtzJuuxbn2emZUCUK, status=0, email=null, phonenumber=null, sex=null, avatar=null, userType=1, createBy=null, createTime=null, updateBy=null, updateTime=null, delFlag=0), permissions=[test, admin], authorities=[test, admin]), Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[test, admin]]

注意:这里如果调用authentication.toString()这个函数,就会调用LoginUser中的getAuthorities函数内容

(4)redis保存结果,返回登录成功

这里通过对userid的一个jwt加密创建出一个token,然后将token值保存到HashMap之中,最后返回登录成功响应

//如果认证通过,使用userId生成一个jwt,jwt存入ResponseResult返回
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
String userid = loginUser.getUser().getId().toString();
String jwt = JwtUtil.createJWT(userid);
//把完整的用户信息存入redis之中,userId作为key,
Map<String,String> map = new HashMap<>();
map.put("token",jwt);
//把完整的用户信息存入redis,userId作为key,这里面的键值对键为token值为jwt
redisCache.setCacheObject("login:"+userid,loginUser);
//这里必须打开redis,才能够保存得上
return new ResponseResult(200,"登录成功",map);

2.第二次登录调用

第二次登录的时候需要在headers之中加入token头,直接访问hello接口部分
Spring Security安全登录的调用过程以及获取权限的调用过程,spring安全代码笔记,spring,安全,java
进入到doFilterInternal函数之中运行,首先获取token的内容,然后根据token解析出userId的内容

//1.获取token
String token = httpServletRequest.getHeader("token");
if(!StringUtils.hasText(token))
{
    filterChain.doFilter(httpServletRequest,httpServletResponse);
    //这里可以放行的原因在于后面还有FilterSecurityInterceptor等其他过滤器,
    //如果没有认证后面还会被拦截下来
    return;
    //这里如果没有return,响应回来之后还会调用后面的代码
}

String userId;
//2.解析token(响应不为空)
try {
    Claims claims = JwtUtil.parseJWT(token);
    userId = claims.getSubject();
    //这里parseJWT就是一个解析过程,不需要过多深究
} catch (Exception e) {
    e.printStackTrace();
    throw new RuntimeException("token非法");
}

获取到userId之后,从redis中根据userId找寻到对应的LoginUser类别

String rediskey = "login:"+userId;
LoginUser loginUser = redisCache.getCacheObject(rediskey);
if(Objects.isNull(loginUser))
{
    throw new RuntimeException("用户未登录");
}

接下来将loginUser封装成为UsernamePasswordAuthenticationToken类

UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());

然后判断UsernamePasswordAuthentication是否能够通过安全认证

SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

这里由于hello接口上面标注了@PreAuthorize(“hasAuthority(‘test’)”),因此可以成功放行
完整的调用过程如下图所示
Spring Security安全登录的调用过程以及获取权限的调用过程,spring安全代码笔记,spring,安全,java文章来源地址https://www.toymoban.com/news/detail-700549.html

到了这里,关于Spring Security安全登录的调用过程以及获取权限的调用过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【深入浅出 Spring Security(四)】登录用户数据的获取,超详细的源码分析

    在【深入浅出Spring Security(一)】Spring Security的整体架构 中叙述过一个SecurityContextHolder 这个类。说在处理请求时,Spring Security 会先从 Session 中取出用户登录数据,保存到 SecurityContextHolder 中,然后在请求处理完毕后,又会拿 SecurityContextHolder 中的数据保存到 Session 中,然后再

    2024年02月07日
    浏览(43)
  • Spring Security 和 Apache Shiro 登录安全架构选型

    Spring Security和Apache Shiro都是广泛使用的Java安全框架,它们都提供了许多功能来保护应用程序的安全性,包括身份验证、授权、加密、会话管理等。 Spring Security和Apache Shiro都是非常常用的登录安全框架,两者在登录安全架构的选型上各有特点: Spring Security特点: 与Spring框架深度集

    2024年02月14日
    浏览(34)
  • Spring项目使用Redis限制用户登录失败的次数以及暂时锁定用户登录权限

    前两天被面试到这个问题,最初回答的不是很合理,登录次数这方面记录还一直往数据库上面想,后来感觉在数据库中加一个登录日志表,来查询一段时间内用户登录的次数,现在看来,自己还是太年轻了,做个登录限制肯定是为了防止数据库高并发,加一个表来记录登录日

    2024年02月12日
    浏览(50)
  • Spring security权限管理

    主要内容 一、Spring Security简介 1.概括 ​ Spring Security是一个高度自定义的 安全框架 。利用Spring IoC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。 ​ 使用Spring Secruity的原因有很多,但大部分都是发现了javaEE的Servlet规范或

    2024年02月03日
    浏览(35)
  • 13.Spring security权限管理

    13.1什么是权限管理 Spring security支持多种不同的认证方式,但是无论开发者使用哪种认证方式,都不会影响授权功能的使用,spring security很好地实现了认证和授权两大功能的解耦。 13.2Spring security权限管理策略 从技术上来说,spring security中提供的权限管理功能主要有两种类型

    2023年04月12日
    浏览(73)
  • 【Spring Security系列】一文带你了解权限框架与Spring Security核心概念

    权限框架是软件开发中用于管理 用户权限和访问控制 的工具。在企业或者我们毕设复杂的系统中,不同的用户或角色需要拥有不同的访问和操作权限,以确保系统的安全性和数据完整性。今天我们就讨论一下Java中的安全框架! 在企业的开发中,Spring Security,Shiro都是比较流

    2024年04月16日
    浏览(38)
  • Spring Security--守护你的功能权限

    首先,让我们明确一下什么是Spring Security以及前后端分离路径拦截器。Spring Security是一个基于Spring框架的安全框架,它提供了一系列的安全服务,包括但不限于认证、授权、加密和会话管理等。而前后端分离路径拦截器是指在前后端分离的情况下,根据用户角色和权限对请求

    2024年02月06日
    浏览(44)
  • Spring Security之基于HttpRequest配置权限

    今天我们重点聊聊授权方式的另外一种:基于HttpServletRequest配置权限 一个典型的配置demo 从这里也可以看出,要实现基于RBAC,还是比较容易的。也比较容易使用。但是如果想要动态的增加角色,就需要我们定制AuthorizationManager。 HttpSecurity是负责构建DefaultSecurityFilterChain的。而

    2024年04月11日
    浏览(40)
  • SpringBoot整合Spring Security实现权限控制

    要对Web资源进行保护,最好的办法莫过于Filter 要想对方法调用进行保护,最好的办法莫过于AOP。 Spring Security进行认证和鉴权的时候,就是利用的一系列的Filter来进行拦截的。 如图所示,一个请求想要访问到API就会从左到右经过蓝线框里的过滤器,其中 绿色部分是负责认证的

    2024年02月15日
    浏览(35)
  • springboot整合security,mybatisPlus,thymeleaf实现登录认证及用户,菜单,角色权限管理

    本系统为springboot整合security,mybatisPlus,thymeleaf实现登录认证及用户,菜单,角色权限管理。页面为极简模式,没有任何渲染。 源码:https://gitee.com/qfp17393120407/spring-boot_thymeleaf 架构截图 此处以用户表为例,其他表数据可在源码获取。 用户表 共用属性 共用属性自动填充配置

    2024年02月07日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包