前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringSecurity入坑(四)

SpringSecurity入坑(四)

作者头像
是小张啊喂
发布2021-08-09 17:36:39
3190
发布2021-08-09 17:36:39
举报
文章被收录于专栏:软件软件

之前都是讲权限写死在配置config中,现在将权限读取出来,并且加上图形验证码做登录检查,关于图形验证码很多,介绍起来就没啥意思了,根据上一个章节说的 图形验证码 整合在这个SpringSecurity 中 [自行参考] ,我们主要来看一下 SpringSecurity 是如何整合 这样一个图形验证的,整合之前,我们需要一个filter拦截器,去拦截这样一个请求

VerificationCodeFilter

代码语言:javascript
复制
package com.shaojie.authority.filter;

import cn.hutool.core.util.StrUtil;
import com.shaojie.authority.exception.VerificationCodeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author: ShaoJie
 * @data: 2020年02月09日 16:40
 * @Description: 图形验证码过滤器
 * <p>
 * OncePerRequestFilter 可以确保一次请求只会通过一次该过滤器 (Filter 在实际的操作中并不能保证这一点)
 */
@Slf4j
public class VerificationCodeFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        // 非登录请求不校验当前的值
        if (!"/index".equals(request.getRequestURI())) {
            // 放行
            filterChain.doFilter(request, response);
        } else {
            verificationCode(request);
            filterChain.doFilter(request, response);
        }
    }

    public void verificationCode(HttpServletRequest request) throws VerificationCodeException {
        // 后去验证表单的值 --> 图形验证码
        String captcha = request.getParameter("captcha");
        log.info("表单的验证码: {}",captcha);
        // 取出 访问时 已经添加在 session 中的验证码
        String sessionCaptcha = (String) request.getSession().getAttribute("captcha");
        log.info("session的验证码: {}",sessionCaptcha);
        // 判断两次的值是否值一样的
        if (!StrUtil.isEmpty(sessionCaptcha)) {
            // 清楚当前的验证码 无论是否成功或是失败 客户端登录失败应刷新当前的验证码
            request.getSession().removeAttribute("captcha");
        }
        // 表单提交的验证码 session 中的验证码 两者均不能为空 且两者需一致
        if (StrUtil.isEmpty(captcha) || StrUtil.isEmpty(sessionCaptcha) || !captcha.equals(sessionCaptcha)) {
            // 这里有个问题 不管是任何时候都会校验这个图形验证码 需要判断一下请求的路径
            throw new VerificationCodeException();
        }
    }
}

这里需要手动抛出验证异常 new VerificationCodeException()

代码语言:javascript
复制
package com.shaojie.authority.exception;

import javax.security.sasl.AuthenticationException;

/**
 * @author: ShaoJie
 * @data: 2020年02月09日 16:38
 * @Description: 校验失败异常
 * <p>
 * 定义一个验证码校验失败的异常
 */
public class VerificationCodeException extends AuthenticationException {

    public VerificationCodeException() {
        super("图形验证码校验失败");
    }

}

这里还需要说明一下关于从session中获取这个验证码的问题,这里就是图形验证码一章中所提到的讲请求到的验证码保存到session中,整合起来一起看,不然可能会很奇怪,这个session中的验证码是怎么来的,还有一个就是表单的验证码,直接看一下登录表单吧

login.html

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>登录页面</h2>
    <form th:action="@{/index}" method="post">
        账号:<input type="text" name="userName" value="1591313226@163.com"><br>
        密码:<input type="password" name="password" value="123456"><br>
        <img src="/captcha.jpg" alt="" th:width="150" height="50"><br>
        验证码:<input type="text" name="captcha"><br>
        <button type="submit">登录</button>
    </form>
</body>
</html>

多加了一个对图形验证码的请求,将图片展示到页面上,每次请求都会重新请求一次这个图片。 后面 就是怎么和当前的这个SpringSecurity整合了,我们只需要将当前的拦截器加入到这个登录拦截器之前即可,也就是在这个SpringSecurityConfig配置当中,并且在这里的权限也将会从数据库读取,而不是写死了

权限范围实体 Purview

代码语言:javascript
复制
package com.shaojie.authority.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.persistence.*;
import java.io.Serializable;

/**
 * @author: ShaoJie
 * @data: 2020年02月10日 14:55
 * @Description: 权限范围及路径
 */
@Data
@Entity
@AllArgsConstructor
@Accessors(chain = true)
@Table(name = "purview")
public class Purview implements Serializable {

    private static final long serialVersionUID = 8025367145943417425L;

    /**
     * 路径自增 id
     */
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    /**
     * 路径
     */
    @Column(name = "url")
    private String url;

    /**
     * 路径权限
     */
    @Column(name = "authority")
    private String authority;

    public Purview() {

    }
}

SpringSecurityConfig配置

代码语言:javascript
复制
    /**
     * 验证
     *
     * @param http
     * @throws Exception
     */
    // 代替配置文件 <security:http></security:http>
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 添加权限
        selectPurview(http);

        http.authorizeRequests()
                // antMatchers 设置拦截的请求  hasAnyAuthority 对应的权限名称
                // .hasAnyAuthority("PRODUCT_ADD") 用户所具有的权限
                // 可替换成 .hasRole() 针对角色做验证
//                .antMatchers("/product/add").hasAnyAuthority("PRODUCT_ADD")
//                .antMatchers("/product/update").hasAnyAuthority("PRODUCT_UPDATE")
//                .antMatchers("/product/list").hasAnyAuthority("PRODUCT_LIST")
//                .antMatchers("/product/delete").hasAnyAuthority("PRODUCT_DELETE")
                // permitAll 所有的权限都能访问
                .antMatchers("/login").permitAll()
                .antMatchers("/captcha.jpg").permitAll()
//                .antMatchers("/**")
                // fullyAuthenticated 不允许匿名用户查看
//                .fullyAuthenticated()
                // 设置所有的请求都必须经过验证才能访问
                .anyRequest().authenticated()
                .and()
                // httpbasic 登录
                // .httpBasic();
                // 表单登录
                .formLogin()
                //  登录请求的页面
                .loginPage("/login")
                // 处理登录请求的 地址
                .loginProcessingUrl("/index")
                // 定义 故障处理器
                // .failureHandler()
                // 修改 spring 提供的 默认登陆参数
                .usernameParameter("userName")
                .passwordParameter("password")
                .and()
                // 开启记住我功能
                .rememberMe()
                .and()
                // 开启登出
                .logout()
                .and()
                //添加过滤器 将 过滤器添加在 UsernamePasswordAuthenticationFilter 之前 也就是在验证账号密码之前
                .addFilterBefore(new VerificationCodeFilter(),
                        UsernamePasswordAuthenticationFilter.class)
                // 禁用跨域的保护
                .csrf().disable();
    }

    /**
     * 查询权限并将权限放入 security 中
     *
     * @param http
     * @throws Exception
     */
    public void selectPurview(HttpSecurity http) throws Exception {
        List<Purview> purviews = purviewService.selectPurview();
        for (Purview purview : purviews) {
            http.authorizeRequests()
                    .antMatchers(purview.getUrl()).hasAnyAuthority(purview.getAuthority());
        }
    }

因为使用的持久层框架是SpringDataJpa所以,也需要修改一下关于用户的enable(账户是否启动)字段,需要在验证登录那里做一下处理,

UserServiceImpl

代码语言:javascript
复制
    /**
     * 根据用户的账号查询用户
     *
     * @param name 用户的账号
     * @return 用户信息
     */
    @Override
    public User findUserByName(String name) {
        Example<User> example = Example.of(new User()
                .setName(name)
                .setEnable(true));
        return userRepository.findOne(example).get();
    }

只有启用的用户才有登录的权限,否则不允许登录,这里根据不同的持久层做调整。

闲聊几句,最近发现这个底层的源码有点难消化,貌似还是没掌握到java的精髓,有点难啃,只能慢慢来了!心急也吃不上热乎的!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • VerificationCodeFilter
  • 这里需要手动抛出验证异常 new VerificationCodeException()
  • login.html
  • 权限范围实体 Purview
  • SpringSecurityConfig配置
  • UserServiceImpl
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档