【SpringSecurity】十三、基于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接口:

在这里插入图片描述

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-20 07:18:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-20 07:18:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-03-20 07:18:03       82 阅读
  4. Python语言-面向对象

    2024-03-20 07:18:03       91 阅读

热门阅读

  1. 【Spring】聊一聊Autowired和Resource

    2024-03-20 07:18:03       43 阅读
  2. ffmpeg 视频拼接 淡入淡出

    2024-03-20 07:18:03       43 阅读
  3. TCP粘包C++进行处理

    2024-03-20 07:18:03       38 阅读
  4. Spring Data访问Elasticsearch----路由值Routing values

    2024-03-20 07:18:03       42 阅读
  5. kafka connect

    2024-03-20 07:18:03       35 阅读
  6. C# double类型计算精度问题解决

    2024-03-20 07:18:03       45 阅读
  7. 面试复盘(北京某小公司)

    2024-03-20 07:18:03       43 阅读
  8. Unity构建详解(2)——SBP的初始设置和脚本编译

    2024-03-20 07:18:03       39 阅读