SpringSecurity权限控制

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

目录

1、Spring Security简介

2、Spring Security实现权限

2.1、Spring Security入门

2.1.1、修改pom文件

2.1.2、添加配置类

2.2、用户认证

2.2.1、自定义组件

2.2.2、核心组件

2.2.3、在配置类配置相关认证类

2.2.4、执行流程

2.3、用户权限

2.3.1、修改UserDetailsService实现类

2.3.2、修改登录过滤器

2.3.3、修改token解析器

2.3.4、修改SpringSecurity配置类

2.3.5、给Controller方法加上权限注解

2.4、自定义权限异常


1、Spring Security简介

Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spring 家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。

正如你可能知道的关于安全方面的两个核心功能是“认证”和“授权”,一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分,这两点也是 SpringSecurity 重要核心功能。

(1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码,系统通过校验用户名和密码来完成认证过程。

通俗点说就是系统认为用户是否能登录

(2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

通俗点讲就是系统判断用户是否有权限去做某些事情。

2、Spring Security实现权限

要对Web资源进行保护,最好的办法莫过于Filter。要想对方法调用进行保护,最好的办法莫过于AOP(面向切面)。而Spring Security进行认证和鉴权的时候,就是利用的一系列的Filter来进行拦截的。

下面是Spring Security过滤器链:

springsecurity权限控制,spring,java,后端

如图所示,一个请求想要访问到API就会从左到右经过蓝线框里的过滤器,其中绿色部分是负责认证的过滤器,蓝色部分是负责异常处理,橙色部分则是负责授权。进过一系列拦截最终访问到我们的API。

springsecurity权限控制,spring,java,后端

这里面我们只需要重点关注两个过滤器即可:

UsernamePasswordAuthenticationFilter负责登录认证,

FilterSecurityInterceptor负责权限授权。

说明:Spring Security的核心逻辑全在这一套过滤器中,过滤器里会调用各种组件完成功能,掌握了这些过滤器和组件你就掌握了Spring Security!这个框架的使用方式就是对这些过滤器和组件进行扩展。

2.1、Spring Security入门

2.1.1、修改pom文件

<dependencies>
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-security</artifactId>
       <version>2.3.6.RELEASE</version>
    </dependency>
<dependencies/>

说明:依赖包(spring-boot-starter-security)导入后,Spring Security就默认提供了许多功能将整个应用给保护了起来:

  • 要求经过身份验证的用户才能与应用程序进行交互
  • 创建好了默认登录表单
  • 生成用户名为user的随机密码并打印在控制台上
  • 等等......

2.1.2、添加配置类

@Configuration
@EnableWebSecurity //@EnableWebSecurity是开启SpringSecurity的默认行为
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

}

随便访问一个我们写好的接口!!

springsecurity权限控制,spring,java,后端

(出现的页面为spring security的默认验证页面),登录的用户名默认为user,密码在项目启动时会在控制台打印,注意每次启动的时候密码都回发生变化!

springsecurity权限控制,spring,java,后端

输入用户名,密码,成功访问到controller方法并返回数据,说明Spring Security默认安全保护生效。

在实际开发中,这些默认的配置是不能满足我们需要的,我们需要扩展Spring Security组件,完成自定义配置,实现我们的项目需求。

2.2、用户认证

用户认证的流程:

springsecurity权限控制,spring,java,后端

以上大部分步骤,spring-security已经给我们完成了,下面是需要我们做的部分:

  • 此处做的登录验证为前后端分离通过请求头是否携带token进行认证

2.2.1、自定义组件

拓展security用户名密码封装对象User

/**
 * spring-security专用实体对象
 */
public class CustomUser extends User {

    /**
     * 我们自己的用户实体对象,要调取用户信息时直接获取这个实体对象。(这里我就不写get/set方法了)
     */
    private SysUser sysUser;

    public CustomUser(SysUser sysUser, Collection<? extends GrantedAuthority> authorities) {
        super(sysUser.getUsername(), sysUser.getPassword(), authorities);
        this.sysUser = sysUser;
    }

    public SysUser getSysUser() {
        return sysUser;
    }

    public void setSysUser(SysUser sysUser) {
        this.sysUser = sysUser;
    }

}

重写通过用户名获取用户信息的方法(userDetailsService中的loadUserByUsername)

这里是通过用户名进行数据库查询

/**
 * 根据用户名得到用户信息
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private SysUserService sysUserService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser sysUser= sysUserService.getByUserName(username);
        if(sysUser==null){
            throw new UsernameNotFoundException("该用户名不存在");
        }

        if(sysUser.getStatus().longValue()==0){
            throw new RuntimeException("账号已停用!");
        }
        return new CustomUser(sysUser, Collections.emptyList());
    }
}

重写密码校验规则

这里使用md5加密

/**
 * 密码校验器:对输入的密码和数据库中的密码进行比较
 */
@Component
public class CustomMd5PasswordEncoder implements PasswordEncoder {
    /**
     * 将用户输入的密码进行加密处理
     * @param rawPassword
     * @return
     */
    public String encode(CharSequence rawPassword) {
        return DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes());
    }

    /**
     * 用于密码校验
     * @param rawPassword 用户输入的密码
     * @param encodedPassword 通过用户名查询数据库获得的密码
     * @return
     */
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equals(DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes()));
    }
}

2.2.2、核心组件

编写登录过滤器

继承UsernamePasswordAuthenticationFilter,对用户名密码进行拦截登录校验

/**
 * <p>
 * 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行拦截登录校验
 * </p>
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    /**
     * 指明校验的页面
     * @param authenticationManager 里面有密码校验的一系列方法:可以理解为校验者
     */
    public TokenLoginFilter(AuthenticationManager authenticationManager) {
        this.setAuthenticationManager(authenticationManager);//设置校验者
        this.setPostOnly(false);
        //指定登录接口及提交方式,可以指定任意路径
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login","POST"));
    }

    /**
     * 登录认证
     * @param req
     * @param res
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException {
        try {
            //通过流的方式将请求的对象封装为指定对象
            LoginVo loginVo = new ObjectMapper().readValue(req.getInputStream(), LoginVo.class);
            //将指定对象的用户名和密码封装为Authentication对象
            Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
            //调用authenticate方法完成验证
            Authentication authenticate = this.getAuthenticationManager().authenticate(authenticationToken);
            return authenticate;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 登录成功
     * @param request
     * @param response
     * @param chain
     * @param auth
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication auth) throws IOException, ServletException {
        //获取验证成功的对象
        CustomUser customUser = (CustomUser) auth.getPrincipal();
        //生成token
        String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());
        //以原生的方式返回token
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        ResponseUtil.out(response, Result.success(map));
    }

    /**
     * 登录失败
     * @param request
     * @param response
     * @param e
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException e) throws IOException, ServletException {

        if(e.getCause() instanceof RuntimeException) {
            ResponseUtil.out(response, Result.build(null, 204, e.getMessage()));
        } else {
            ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
        }
    }
}

编写token解析器(将认证成功对象传至上下文中)

并且将authentication对象保存至SecurityContext上下文中

/**
 * <p>
 * 认证解析token过滤器
 * </p>
 */
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    public TokenAuthenticationFilter() {

    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.info("uri:"+request.getRequestURI());
        //如果是登录接口,直接放行
        if("/admin/system/index/login".equals(request.getRequestURI())) {
            chain.doFilter(request, response);
            return;
        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(request);//获取请求的对象封装为spring-security的对象
        //如果对象存在
        if(null != authentication) {
            SecurityContextHolder.getContext().setAuthentication(authentication);//将对象存至SecurityContext(上下文均可使用)
            chain.doFilter(request, response);//对所有资源进行放行
        } else {
            ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
        }
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        // token置于header里
        String token = request.getHeader("token");
        logger.info("token:"+token);
        if (!StringUtils.isEmpty(token)) {
            String useruame = JwtHelper.getUsername(token);
            logger.info("useruame:"+useruame);
            if (!StringUtils.isEmpty(useruame)) {
                return new UsernamePasswordAuthenticationToken(useruame, null, Collections.emptyList());
            }
        }
        return null;
    }
}

2.2.3、在配置类配置相关认证类

@Configuration
@EnableWebSecurity //@EnableWebSecurity是开启SpringSecurity的默认行为
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private CustomMd5PasswordEncoder customMd5PasswordEncoder;


    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    //由于博主正在写前后端分离的项目,下面有些不是前后端分离的可以不用加
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 这是配置的关键,决定哪些接口开启防护,哪些接口绕过防护
        http
                //关闭csrf跨站请求伪造
                .csrf().disable()
                // 开启跨域以便前端调用接口
                .cors().and()
                .authorizeRequests()
                // 指定某些接口不需要通过验证即可访问。登陆接口肯定是不需要认证的
                .antMatchers("/admin/system/index/login").permitAll()
                // 这里意思是其它所有接口需要认证才能访问
                .anyRequest().authenticated()
                .and()
                //TokenAuthenticationFilter放到UsernamePasswordAuthenticationFilter的前面,这样做就是为了除了登录的时候去查询数据库外,其他时候都用token进行认证。
                .addFilterBefore(new TokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilter(new TokenLoginFilter(authenticationManager()));

        //禁用session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 指定UserDetailService和加密器
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(customMd5PasswordEncoder);
    }

    /**
     * 配置哪些请求不拦截
     * 排除swagger相关请求
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/favicon.ico","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html");
    }
}

2.2.4、执行流程

下图为当我们访问登录页面时的整个校验流程

springsecurity权限控制,spring,java,后端

2.3、用户权限

想要达到用户权限的管理,我们需要在UserDetailsService实现类中获取到的我们进行用户权限管理的权限数据,并加至security专用对象中进行认证。

springsecurity权限控制,spring,java,后端

2.3.1、修改UserDetailsService实现类

此处将权限数据保存至User对象中

springsecurity权限控制,spring,java,后端

2.3.2、修改登录过滤器

此处通过验证成功将UserDetails对象里面的权限数据存到redis,用于后续的存入SpringSecuritycontext上下文对象中(在构造方法中注明redisTemplate对象,到配置类自动注入)

springsecurity权限控制,spring,java,后端

springsecurity权限控制,spring,java,后端

2.3.3、修改token解析器

此处从redis中通过用户名获取权限数据并封装为上下文专用对象返回

springsecurity权限控制,spring,java,后端

2.3.4、修改SpringSecurity配置类

springsecurity权限控制,spring,java,后端

2.3.5、给Controller方法加上权限注解

springsecurity权限控制,spring,java,后端文章来源地址https://www.toymoban.com/news/detail-602401.html

2.4、自定义权限异常

    /**
     * 自定义权限异常
     * @param e
     * @return
     * @throws AccessDeniedException
     */
    @ExceptionHandler(AccessDeniedException.class)
    public Result error(AccessDeniedException e) throws AccessDeniedException {
        return Result.build(null).code(204).message("没有权限访问");
    }

到了这里,关于SpringSecurity权限控制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • java【毕业设计】项目-第118期基于SpringBoot+LayUI的视频播放网站(权限采用SpringSecurity)-计算机毕业设计

    java【毕业设计】项目-第118期基于SpringBoot+LayUI的视频播放网站(权限采用SpringSecurity) 【源码请到资源专栏下载】 Hi,大家好,今天分享的源码是《基于SpringBoot+LayUI的视频播放网站》。 支持本地资源视频文件上传在线播放,同时支持在线资源链接上传(ed2k、迅雷、等资源)下

    2023年04月10日
    浏览(48)
  • 万字长文,SpringSecurity实现权限系统设计

    RBAC 全称为基于角色的权限控制,本段将会从什么是RBAC,模型分类,什么是权限,用户组的使用,实例分析等几个方面阐述RBAC 绘制思维导图如下 RBAC 全称为用户角色权限控制,通过角色关联用户,角色关联权限,这种方式,间阶的赋予用户的权限,如下图所示 对于通常的系

    2024年02月11日
    浏览(46)
  • SpringSecurity登录验证没有权限的问题(403)

    SpringSecurityConfig配置登录验证拦截,并放行登录验证及生成二维码的url。 调用postman 测试接口,发现可以获取验证码。 但当进行登录验证的时候就报了403错误,没有走过滤器,而是是直接走了配置中的accessDeniedHandler方法,返回403。 当使用get接口发现走了过滤器,但是因为S

    2024年02月11日
    浏览(32)
  • 第2讲springsecurity+vue通用权限系统

    阿里云 maven阿里云镜像 pom.xml 主键自增 删除test测试包

    2024年02月20日
    浏览(29)
  • SpringBoot3整合SpringSecurity,实现自定义接口权限过滤

    接口权限过滤是指对于某些接口或功能,系统通过设定一定的权限规则,只允许经过身份认证且拥有相应权限的用户或应用程序进行访问和操作 。这种技术可以有效地保护系统资源和数据安全,防止未授权的用户或程序进行恶意操作或非法访问。通常情况下,接口权限过滤需

    2024年02月08日
    浏览(53)
  • 权限管理 springboot集成springSecurity Oauth2 JWT

    目录 一、SpringSeurity的基础操作 1、引入主要依赖 2、加密器 3、实现自定义登录逻辑 4、访问限制 5、自定义异常处理  6、通过注解的方式配置访问控制 二、Auth2认证方案 1、什么是Auth2认证 2、Oauth2最常用的授权模式  3、依赖引入 4、添加配置类 5、测试 6、存在到Redis里,后续

    2023年04月14日
    浏览(45)
  • springsecurity记住我登录时访问无权限接口,跳转登录界面

    贴一下springsecurity无权限时异常处理的逻辑 未登录状态:如果用户尝试访问需要认证的资源但未登录,即未经过认证,在这种情况下应该跳转到登录页面或者返回登录提示,让用户进行身份验证。通过调用 AuthenticationEntryPoint 可以统一处理未登录状态下的跳转逻辑,确保用户

    2024年02月21日
    浏览(37)
  • SpringSecurity源码分析(一) SpringBoot集成SpringSecurity即Spring安全框架的加载过程

          Spring Security是一个强大的并且高度可定制化的访问控制框架。 它基于spring应用。 Spring Security是聚焦于为java应用提供授权和验证的框架。像所有的spring项目一样,Spring Security真正的强大在于可以非常简单的拓展功能来实现自定义的需求。       在分析SpringBoot集成的Sp

    2024年02月03日
    浏览(46)
  • SpringBoot集成SpringSecurity从0到1搭建权限管理详细过程(认证+授权)

    最近工作需要给一个老系统搭建一套权限管理,选用的安全框架是SpringSecurity,基本上是结合业务从0到1搭建了一套权限管理,然后想着可以将一些核心逻辑抽取出来写一个权限通用Demo,特此记录下。 Spring Security是 Spring家族中的一个安全管理框架。相比与另外一个安全框架

    2024年02月04日
    浏览(43)
  • 权限认证SpringCloud GateWay、SpringSecurity、OAuth2.0、JWT一网打尽!

    1.它是如何工作的? ​ 客户端向 Spring Cloud Gateway 发出请求。如果Gateway处理程序映射确定一个请求与路由相匹配,它将被发送到Gateway Web处理程序。这个处理程序通过一个特定于该请求的过滤器链来运行该请求。过滤器被虚线分割的原因是,过滤器可以在代理请求发送之前和

    2024年04月08日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包