【Spring Security】安全框架学习(八)

这篇具有很好参考价值的文章主要介绍了【Spring Security】安全框架学习(八)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

3 授权

3.0 权限系统的作用

例如一个学校图书馆的管理系统,如果是普通学生登录就能看到借书还书相关的功能,不可能让他看到并且去使用添加书籍信息,删除书籍信息等功能。但是如果是一个图书馆管理员的账号登录了,应该就能看到并使用添加书籍信息,删除书籍信息等功能。

总结起来就是不同的用户可以使用不同的功能。这就是权限系统要去实现的效果。

我们不能只依赖前端去判断用户的权限来选择显示哪些菜单哪些按钮。因为如果只是这样,如果有人知道了对应功能的接口地址就可以不通过前端,直接去发送请求来实现相关功能操作。实际上前端的校验防君子不防小人。

所以我们还需要在后台进行用户权限的判断,判断当前用户是否有相应的权限,必须基于所需权限才能进行相应的操作。

3.1 授权的基本流程

在SpringSecurity中, 会使用默认的FilterSecuritylnterceptor来进行权限校验。 在FilterSecuritylnterceptor中会从SecurityContextHolder获取其中的Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。

所以我们在项目中只需要把当前登录用户的权限信息也存入Authentication。

然后设置我们的资源所需要的权限即可。

这部分的工作实际上就是完善前面 UserDetailsServiceImpl 和 JwtAuthenticationTokenFileter 中的TODO。

3.2 授权实现

3.2.1 限制访问资源所需权限

SpringSecurity为我们提供了基于注解基于配置两种权限控制方案。这我们项目中主要采用的方式是基于注解的。因为使用配置的方式往往是配置静态资源的,前后端分离项目很少使用,所以我们可以使用注解去指定访问对应的资源所需的权限。

在前面部分的代码中,我们会把权限信息写死,实际上权限应该是从数据库中拿到的。

但是要使用它,我们需要先开启相关配置(在SecurityConfig配置类中)。

@EnableGlobalMethodSecurity(prePostEnabled = true)

然后就可以使用对应的 @PreAuthorize 注解。示例如下:

@RestController
public class Hellocontroller {
	
    @RequestMapping("/hello")
	@PreAuthorize("hasAuthority('test')")
	public String hel1o(){
		return "hello";
    }
}

3.2.2封装权限信息

我们前面在写UserDetailsServicelmpl的时候说过,在查询出用户后还要获取对应的权限信息,封装到UserDetails中返回。

我们先直接把权限信息写死封装到UserDetails中进行测试。

之前定义了UserDetails的实现类LoginUser,想要让其能封装权限信息就要对其进行修改。

UsernamePasswordAuthenticationToken方法所使用的三个形参及其含义如下表所示。

形参名 含义
loginUser 用户名
credentials 密码
authorities 权限信息

修改后的LoginUser类:

package domain;

import ...
    
/**
 * UserDetails的实现类
 */
    
@Data
@NoArgsConstructor
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;
    }

    //重写方法
    @JSONField(serialize = false)
    private List<SimpleGrantedAuthority> authorities;
    
    @Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
        //把 permissions 中的String类型的权限信息封装成SimpleGrantedAuthority对象
       //两种写法,一种是使用for循环遍历集合,一种是使用stream流,这里两种写法都给出,但推荐使用Stream流的写法
		
        if(authorities != null) {
            return authorities;
        }
        /**
         * //写法一
         * newList = new ArrayList<>();
		 * for (String permission: permissions){
		 * 		SimpleGrantedAuthority authority = new SimpleGrantedAuthority (permission);
		 * 		newList.add(authority);
		 * }
		 */
        
        //方法二
        authorities = permissions.stream()
            .map (Simp leGrantedAuthority::new)
            .collect(Collectors.toList());

         return authorities;
        
    }
    
	@Override
	public String getPassword() {
		return user.getPassword();
    }

	@Override
	public String getUsername() {
		return user.getUserName();
    }
    
	@Override
	public boolean isAccountNonExpired(){
		return true;
    }
    
    @Override
	public boolean isAccountNonLocked(){
		return true;
    }
    
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
    }
	
    @Override
	public boolean isEnabled(){
		return true;
	}
}

在上面的代码中,我们可以看到一个泛型 SimpleGrantedAuthority ,它是由Spring提供的,但是我们在存储进redis中的时候,为了安全考虑,默认情况下是不会把SimpleGrantedAuthority进行序列化存入的,如果不做操作的话,java会报异常。

解决的方案就是将 authorities 不存入redis当中,只用把 permissions 序列化存入即可。这里我们对它进行一个忽略,由 @JSONField(serialize = false) 实现

如果加了注解还是报错: default constructor not found。可以把fastjson的版本改成1.2.49。

修改后的UserDetailsServiceImpl

package service.impl;

import ...

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
	
    @Autowired
    private UserMapper userMapper;
    
    @Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        private UserMapper 
        
        //查询用户信息
        LambdaQueryWrapper<User> queryWeapper=new LambdaQueryWrapper();
        queryWrapper.eq(User::getUserName,username);
        User user = userMapper.selectOne(queryWrapper);
        
        //如果没有查询到用户,就抛出异常
        if(Object.isNull(user)) {
            throw new RuntimeException("用户名或密码错误");
        }
        
  		//TODO 查询对应的权限信息,此处这么写是为了方便测试
		List<String> list = new ArrayList<>(Arrays.asList("test","admin"));
        
        //把数据封装成UserDetails返回
        return new LoginUser(user, list);
	}
}

上面是登陆的方法要为增加权限做的修改。

我们的代码中还有一个 TODO ,是在 JwtAuthenticationTokenFilter 认证过滤器中。文章来源地址https://www.toymoban.com/news/detail-488324.html

package filter;

import ...

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
    
    @Autowired
	private RedisCache redisCache;
    
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain
filterChain) throws ServletException, IOException {
		
        //直接放行不等于不设置SecurityContextHolder,不设置SecurityContextHolder就没法通过认证到达Api,会被后面的filter给拦住
        
        //获取请求头中的token
		String token = request.getHeader("token");
		if(!Stringutils.hasText(token)){
            //放行
			filterchain.doFilter(request,response);
            //过滤器中doFilter方法前面的逻辑是请求进来时执行的内容,doFilter后面的逻辑是响应时执行的内容,直接return了,响应时就不会执行后面的内容了
			return;
        }

        //解析token获取userid
		string userId;
		try {
			Claims claims = JwtUtil.parseJWT(token);
			userId = claims.getsubject();       
        } catch(Exception e) {
            e.printStackTrace();
            throw new RuntimeException("token非法");
        }
        
        //通过 userId 从redis中获取用户信息
        String redisKey = "login:"+userId;
        LoginUser loginUser = redisCache.getCacheObject(redisKey);
        if(Object.isNull(loginUser)) {
            throw new RuntimeException("用户未登录");
        }
        
        //如果从redis中获取到loginUser,就存入SecurityContextHolder
        //TODO 获取权限信息封装到Authentication中
        //前面登录时用两参,对认证状态还未确认,之后调用ProviderManager对账号密码进行确认后,返回的那个Authentication是认证的。
       UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities); 
       SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //放行
        filterchain.doFilter(request,response);
    }

}

到了这里,关于【Spring Security】安全框架学习(八)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Spring Security 6.x 系列【51】授权篇之动态权限规则

    有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列Spring Security 版本 6.1.0 源码地址:https://gitee.com/pearl-organization/study-spring-security-demo 在开始阅读本篇文档前,您需要了解以下文档的相关知识: Spring Security 6.x 系列【16】授权篇之访问控制 Spring Securi

    2024年02月07日
    浏览(61)
  • 【深入浅出 Spring Security(十一)】授权原理分析和持久化URL权限管理

    在 【深入浅出Spring Security(一)】Spring Security的整体架构 中小编解释过授权所用的三大组件,在此再解释说明一下(三大组件具体指:ConfigAttribute、AccessDecisionManager(决策管理器)、AccessDecisionVoter(决策投票器)) ConfigAttribute 在 Spring Security 中,用户请求一个资源(通常是

    2024年02月10日
    浏览(61)
  • 【Spring Security系列】一文带你了解权限框架与Spring Security核心概念

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

    2024年04月16日
    浏览(40)
  • Spring Security(安全框架)

    (1)Spring Security 是一个高度自定义的 安全框架 。利用Spring IoC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。 (2)认证(Authentication): 应用程序确认用户身份的过程,常见认证:登录。 (3)身份(principal)/主体(

    2023年04月13日
    浏览(74)
  • Spring Security安全登录的调用过程以及获取权限的调用过程

    (0)权限授理 首先调用SecurityConfig.java中的config函数将jwtAuthenticationTokenFilter过滤器放在UsernamePasswordAuthenticationFilter之前 (1)首先运行JwtAuthenticationTokenFilter extends OncePerRequestFilter中的doFilterInternal函数 这里由于没有获取到token,因此调用!StringUtils.hasText(token),这里使用 继续运行其他

    2024年02月09日
    浏览(42)
  • 后端进阶之路——Spring Security构建强大的身份验证和授权系统(四)

    「作者主页」 :雪碧有白泡泡 「个人网站」 :雪碧的个人网站 「推荐专栏」 : ★ java一站式服务 ★ ★ 前端炫酷代码分享 ★ ★ uniapp-从构建到提升 ★ ★ 从0到英雄,vue成神之路 ★ ★ 解决算法,一个专栏就够了 ★ ★ 架构咱们从0说 ★ ★ 数据流通的精妙之道★ ★后端进

    2024年02月14日
    浏览(53)
  • Shiro和Spring Security安全框架对比

    Apache Shiro是Java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单。与Spring Security对比,Shiro可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。下面对这两个安全框架进行了对比,可以

    2024年02月10日
    浏览(42)
  • 【Spring Security】让你的项目更加安全的框架

    🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《Spring Security》。🎯🎯 👉点击这里,就可以查看我的主页啦!👇👇 Java方文山的个人主页 🎁如果感觉还不错的话请给我点赞吧!🎁🎁 💖期待你的加入,一

    2024年02月04日
    浏览(58)
  • SSM+Shiro安全框架整合(完成安全认证--登录+权限授权)+ssm整合shiro前后端分离

    目录 1.搭建SSM框架  1.1.引入相关的依赖 1.2. spring配置文件 1.3. web.xml配置文件 1.4.配置Tomcat并启动 2.ssm整合shiro---认证功能  (1).引入依赖 (2).修改spring配置文件 (3).修改web.xml文件 (4).新建login.jsp(登录页面) (5).新建success.jsp(登录成功后跳转到此) (6).创建User实体类 (7).创建LoginVo

    2024年02月15日
    浏览(46)
  • Spring Boot 优雅集成 Spring Security 5.7(安全框架)与 JWT(双令牌机制)

    本章节将介绍 Spring Boot 集成 Spring Security 5.7(安全框架)。 🤖 Spring Boot 2.x 实践案例(代码仓库) Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。 它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring

    2024年02月12日
    浏览(57)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包