文章目录
- 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"));}@Overridepublic 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 {@Resourceprivate AuthenticationService authenticationService;@GetMapping(value = "/login")public String login(AuthenticationRequestDto dto, HttpSession session) {UserVo userVo = authenticationService.auth(dto);//用户信息存入sessionsession.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是否在权限范围中*/@Overridepublic 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;//请求的urlString 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 {/*** 视图解析器*/@Beanpublic InternalResourceViewResolver viewResolver(){InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setPrefix("/static/"); //前缀viewResolver.setSuffix(".jsp"); //后缀return viewResolver;}@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("login");}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SimpleAuthInterceptor()).addPathPatterns("/r**"); //新加进来的拦截器只针对r打头的接口,否则login接口也会被拦截要求登录}
}
测试,登录zhangsan,其有r1权限,访问r2接口: