Spring Security进行权限控制

2年前 (2022) 程序员胖胖胖虎阿
185 0 0

一、SpringSecurity介绍

  • 简介
    SpringSecurity是一个专注于java应用程序提供身份认证和授权的框架,它的强大之处在于它可以轻松扩展以满足自定义的需求
  • 特征
    – 对身份的认证授权提供全面的、可扩展的支持。
    – 防止各种攻击,如会话固定攻击、点击劫持、csrf攻击等。
    – 支持与Servlet API,Spring MVC等web技术支持
  • SpringSecurity底层是通过11钟过滤器进行实现,属于JavaEE层面
    Spring Security进行权限控制
    SpringSecurity底层详解网站推荐:http://www.spring4all.com/article/428

二、利用SpringSecurity进行权限控制

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

编写config类

对未登录,权限不足以及退出时进行过滤

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter implements CommunityConstant {
    //忽略对静态资源的拦截
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //授权
        http.authorizeRequests()
                //需要授权的请求
                .antMatchers(
                        "/user/setting",
                        "/user/upload",
                        "/discuss/add",
                        "/comment/add/**",
                        "/letter/**",
                        "/notice/**",
                        "/like",
                        "/follow",
                        "/followee/**",
                        "/follower/**"
                )
                //上述请求需要的身份
                .hasAnyAuthority(
                        AUTHORITY_USER,
                        AUTHORITY_ADMIN,
                        AUTHORITY_MODERATOR
                )
                //拥有身份时允许的行为
                .anyRequest().permitAll();

        //权限不够时的操作
        http.exceptionHandling()
                //没有登陆
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
                    @Override
                    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                        //当请求头是x-requested-with=XMLHttpRequest时说明是异步请求,返回JSON字符串
                        String xRequestedWith = request.getHeader("x-requested-with");
                        //if (xRequestedWith.equals("XMLHttpRequest")) {会报空指针异常
                        if ("XMLHttpRequest".equals(xRequestedWith)) {
                            response.setContentType("application/plain;charset=utf-8");
                            PrintWriter writer = response.getWriter();
                            writer.write(CommunityUtil.getJSONString(403, "您还没有登录!"));
                        } else {
                            response.sendRedirect(request.getContextPath() + "/login");
                        }
                    }
                })
                //权限不足
                .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                        //当请求头是x-requested-with=XMLHttpRequest时说明是异步请求,返回JSON字符串
                        String xRequestedWith = request.getHeader("x-requested-with");
                        //if (xRequestedWith.equals("XMLHttpRequest")) {会报空指针异常
                        if ("XMLHttpRequest".equals(xRequestedWith)) {
                            response.setContentType("application/plain;charset=utf-8");
                            PrintWriter writer = response.getWriter();
                            writer.write(CommunityUtil.getJSONString(403, "您没有访问的权限!"));
                        } else {
                            response.sendRedirect(request.getContextPath() + "/denied");
                        }
                    }
                });
        //security底层默认会拦截/logout请求,进行退出处理,覆盖他的逻辑,才能执行我们自己的推出代码
        http.logout().logoutUrl("/securitylogout");//写一个没有的请求欺骗springSecurity
    }
}

if (xRequestedWith.equals(“XMLHttpRequest”)) 会报空指针异常,因为xRequestedWith可能为null
改为if (“XMLHttpRequest”.equals(xRequestedWith)) 防止此错误

编写userService类实现获取用户权限的方法

@Override
public Collection<? extends GrantedAuthority> getAuthorities(int userId) {
    //获得当前登录用户
    User user = this.findUserById(userId);
    //将用户权限装入List
    List<GrantedAuthority> list = new ArrayList<>();
    list.add(new GrantedAuthority() {
        @Override
        public String getAuthority() {
            switch (user.getType()){
                case 1:
                    return AUTHORITY_ADMIN;
                case 2:
                    return AUTHORITY_MODERATOR;
                default:
                    return AUTHORITY_USER;
            }
        }
    });
    return list;
}

将认证信息写入过滤器

写入过滤器的preHandle方法,在每一次请求前都调用

//构建用户认证的结果,并存入SecurityContext,以便于security进行授权
Authentication authentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), userService.getAuthorities());
SecurityContextHolder.setContext(new SecurityContextImpl(authentication));

并在请求结束时的afterCompletion方法中清楚认证

SecurityContextHolder.clearContext();

防止csrf攻击

Spring Security进行权限控制

  • csrf攻击:
    在用户提交表单时,不法网站可能窃取用户提交的信息进行提交从而造成安全问题
  • 解决办法
    springsecurity中在用户同步提交表单时设置了一个隐藏的token,不但会对用户提交的信息进行核实,还会对token进行核实,在异步提交的时候则需要自行在前端加入token提交
  • 异步请求时徐手动添加token的提交
<!--生成csrf令牌-->
<meta name="_csrf" th:content="${_csrf.token}">
<meta name="_csrf_header" th:content="${_csrf.headerName}">
//发送ajax请求前,将csrf令牌设置到请求的消息头中
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function (e, xhr, options) {
	xhr.setRequestHeader(header, token)
})

Spring Security进行权限控制
添加成功

三、整合前端模板

引入依赖

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>

前端引入

<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

模块设置

<button type="button" class="btn btn-danger btn-sm " id="topBtn" th:disabled="${post.type==1}" sec:authorize="hasAnyAuthority('moderator')">置顶</button>

满足moderator权限时才显示

版权声明:程序员胖胖胖虎阿 发表于 2022年10月11日 上午6:24。
转载请注明:Spring Security进行权限控制 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...