当前位置: 首页 > article >正文

【SpringSecurity】十三、基于Session实现授权认证

文章目录

  • 1、基于session的认证
  • 2、Demo
    • session实现认证
    • session实现授权

1、基于session的认证

在这里插入图片描述
流程:

  • 用户认证成功后,服务端生成用户数据保存在session中
  • 服务端返回给客户端session id (sid),被客户端存到自己的cookie中
  • 客户端下次再请求,就带上sid,服务端校验是否存在对应的session,存在则不要求用户再登录了

2、Demo

基于Session的认证机制由Servlet制定规范,Serlvet容器以实现,HttpSession相关方法:

方法用途
HttpSession getSession(Boolean create)获取当前HttpSession对象
void setAttribute(String name,Object value)向session中存放对象
object getAttribute(String name)从session中获取对象
void removeAttribute(String name);移除session中对象
void invalidate()使HttpSession失效

准备实体类:

@Data
public class AuthenticationRequestDto {
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
}

@Data
@AllArgsConstructor
public class UserVo {

    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
}

session实现认证

用Map模拟查询数据库,存储用户信息:

@Service
public class AuthenticationServiceImpl implements AuthenticationService {

    private final Map<String, UserVo> userMap = new HashMap<>();

    {
        userMap.put("zhangsan", new UserVo("1010", "zhangsan", "123", "zhangSan", "133443"));
        userMap.put("lisi", new UserVo("1011", "lisi", "456", "liSi", "144553"));
    }

    @Override
    public UserVo auth(AuthenticationRequestDto dto) {

        if (dto == null
                || StringUtils.isEmpty(dto.getUsername())
                || StringUtils.isEmpty(dto.getPassword())) {
            throw new RuntimeException("账户或密码为空");
        }
        //模拟查询数据库
        UserVo vo = getUserVo(dto.getUsername());
        if (null == vo) {
            throw new RuntimeException("用户不存在");
        }
        if (!vo.getPassword().equals(dto.getPassword())) {
            throw new RuntimeException("密码错误");
        }
        return vo;
    }

    public UserVo getUserVo(String username) {
        return userMap.get(username);
    }

}

定义三个接口,登录,服务端保存session,登出,让session失效。以及一个资源接口,查看当前是登录访问资源,还是未登录访问资源

@RestController
public class Controller {

    @Resource
    private AuthenticationService authenticationService;

    @GetMapping(value = "/login")
    public String login(AuthenticationRequestDto dto, HttpSession session) {
        UserVo userVo = authenticationService.auth(dto);
        //用户信息存入session
        session.setAttribute("sid", userVo);
        return userVo.getFullname() + " success login";
    }

    @GetMapping("/logout")
    public String logout(HttpSession session) {
    	//让session失效
        session.invalidate();
        return " success logout";
    }

    @GetMapping("/r1")
    public String resource(HttpSession session) {
        String fullName = null;
        Object result = session.getAttribute("sid");
        if (result != null) {
            fullName = ((UserVo) result).getFullname();
        } else {
            fullName = "no login";
        }
        return fullName + " access resource ... ";
    }

}

测试:

在这里插入图片描述

登录后访问资源接口:

在这里插入图片描述
退出登录后,再访问资源接口:

在这里插入图片描述
在这里插入图片描述

session实现授权

修改实体类,加个权限字段,存储用户权限

@Data
@AllArgsConstructor
public class UserVo {

    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;

    /**
     * 用户权限
     */
    private Set<String> authorities;
}

实例代码块创建用户到map的代码做调整:

{
        Set<String> auth1 = new HashSet<>();
        auth1.add("p1");   //对应/r1这个接口资源
        Set<String> auth2 = new HashSet<>();
        auth2.add("p2");   //对应/r2这个接口资源
        userMap.put("zhangsan", new UserVo("1010", "zhangsan", "123", "zhangSan", "133443", auth1));
        userMap.put("lisi", new UserVo("1011", "lisi", "456", "liSi", "144553", auth2));
    }

加个测试资源接口/r2

@GetMapping("/r2")
    public String resource2(HttpSession session) {
        String fullName = null;
        Object result = session.getAttribute("sid");
        if (result != null) {
            fullName = ((UserVo) result).getFullname();
        } else {
            fullName = "no login";
        }
        return fullName + " access resource ... ";
    }

写拦截器:

@ComponentScan
public class SimpleAuthInterceptor implements HandlerInterceptor {

    /**
     * 校验用户请求的url是否在权限范围中
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		//从http请求中获取session对象,再拿当前HttpSession对象
        Object object = request.getSession().getAttribute("sid");
        //没有认证
        if (object == null) {
            writeContent(response, "请登录");
        }
        UserVo userVo = (UserVo) object;
        //请求的url
        String requestURI = request.getRequestURI();
        assert userVo != null;
        if (userVo.getAuthorities().contains("p1") && requestURI.contains("/r1")) {
            return true;
        }
        if (userVo.getAuthorities().contains("p2") && requestURI.contains("/r2")) {
            return true;
        }
        //拒绝访问
        writeContent(response,"没有权限,拒绝访问");

        return false;
    }

    private void writeContent(HttpServletResponse response, String msg) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print(msg);
        writer.close();
    }
}

拦截器add并放行/login,只测/r**接口

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    /**
     * 视图解析器
     */
    @Bean
    public InternalResourceViewResolver viewResolver(){
       InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
       viewResolver.setPrefix("/static/");  //前缀
       viewResolver.setSuffix(".jsp");  //后缀
       return viewResolver;
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("login");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SimpleAuthInterceptor()).addPathPatterns("/r**");   //新加进来的拦截器只针对r打头的接口,否则login接口也会被拦截要求登录
    }
}

测试,登录zhangsan,其有r1权限,访问r2接口:

在这里插入图片描述


http://www.kler.cn/a/274634.html

相关文章:

  • 常用Python自动化测试框架有哪些?
  • 基于MATLAB的图像增强
  • aosp15 - Activity生命周期切换
  • 智能工厂的设计软件 三种处理单元(NPU/GPU/CPU)及其在深度学习框架中的作用 之4(百度文库答问 之2)
  • 1小时放弃Rust(2): 两数之和
  • Vue3 的 Teleport 是什么?在什么场景下会用到?
  • 使用OpenRewrite自动做框架升级比如Spring Boot
  • Siloed No More: How AI-Driven Tech Stack Consolidation Boosts Revenue
  • C# 使用OpenCvSharp4将Bitmap合成为MP4视频的环境
  • O2OA红头文件流转与O2OA版式公文编辑器基本使用
  • java基础-Test03:图书管理系统 超详细注释
  • vue-router(v4.0) 基础3
  • Panasonic松下PLC如何数据采集?如何实现快速接入IIOT云平台?
  • fs方法举例
  • 蓝桥杯day4刷题日记
  • 算法笔记p335堆
  • 景联文科技:提供通用多模态数据,助力AI多模态领域实现飞跃式发展
  • CMU 10-414/714: Deep Learning Systems --hw3
  • HTML、XHTML和HTML5 的区别是什么?
  • 《优化接口设计的思路》系列:第九篇—用好缓存,让你的接口速度飞起来
  • Linux运维_Linux临时环境变量设置(bin和include以及lib)
  • Android14音频进阶:AudioFlinger究竟如何混音?(六十三)
  • 开源离线语音识别输入工具CapsWriter v1.0——支持无限时长语音、音视频文件转录字幕。
  • 《论文阅读》端到端情感原因对提取的有效子句间建模
  • 洛谷_P1104 生日_python写法
  • windows搭建Elasticsearch环境