内容概述
上一篇文章主要说明了,如何用很少的代码,通过SpringBoot的自动配置,实现一个读取数据库并返回数据的简单api。
实际应用中,一个web服务都会有用户的注册,登录和鉴权等功能。
这篇文章主要包含这几个功能的简单实现。
1.注册
注册的基本实现是接收到用户名和密码,并把密码加密后保存到数据库,实现如下:
@RestController //定义为rest类型的控制器
public class UserController {
@Resource //注入MainUserService
IMainUserService mainUserService;
@PostMapping("user/register") //定义post请求
public CommonResVo<Boolean> userRegister(@RequestBody MainUser mainUser) throws Exception {
//验证用户名是否已存在
MainUser oldUser = mainUserService.getOne(new LambdaQueryWrapper<MainUser>().eq(MainUser::getUserName, mainUser.getUserName()));
if (oldUser != null) {
throw new Exception("用户已存在");
}
//用户密码存表时,要做加密处理,可以直接使用spring提供的DigestUtils工具类生成32位MD5字符串
String password = DigestUtils.md5DigestAsHex(mainUser.getPassword().getBytes());
mainUser.setPassword(password);
mainUserService.save(mainUser);
return CommonResVo.success(true);
}
}
- controller的方法中,@RequestBody指定使用post请求在body中发送json格式的数据,spring可以直接将同名参数赋值给MainUser的对象
- 例如该请求传入的参数如下:
{
"userName":"test2",
"password":"123456",
"userPhone":"13900010200"
}
- 程序中获取到的对象为:
2.登录
这里使用session作为用户登录后的验证方式,登录成功后会将userId写入session中,生产中的服务基本都是集群的,需要共享session。
在spring中,可以通过配置session starter,很简单的将session信息存储到redis中。
- 需要的starter依赖,因为项目中已经引入了spring-boot-starter-parent指定统一版本,所以这里不需要写版本
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
- application.yml中需要增加的配置
spring:
redis:
database: 0
host: localhost
port: 6379
session:
store-type: redis
timeout: 600s
- 完成上面的配置,就可以通过redis在集群中共享session信息了,登录代码如下:
- 处理Get请求时,可以直接将请求url中的参数赋值给同名的函数参数。该功能主要是通过ParameterNameDiscoverer实现的。
@GetMapping("user/login")
public CommonResVo<Boolean> userRegister(String userName, String password, HttpSession session) throws Exception {
//通过用户名获取用户信息
MainUser mainUser = mainUserService.getOne(new LambdaQueryWrapper<MainUser>().eq(MainUser::getUserName, userName));
if (mainUser == null) {
throw new Exception("用户不存在");
}
//对比MD5密码
String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
if (!mainUser.getPassword().equals(md5Password)) {
throw new Exception("账号名或密码错误");
}
//将userId存入session中,这里会存储到redis中
session.setAttribute("userId", mainUser.getUserId());
return CommonResVo.success(true);
}
3.鉴权
鉴权的过程就是根据请求中的session信息,获取userId,可以获取到,证明已登录,后续根据userId获取用户信息进行逻辑处理。
获取不到,说明已过期或未登录,提示重新登录。
web服务中,大部分接口都需要鉴权,这里使用拦截器实现。
通过实现HandlerInterceptor
接口定义一个拦截器,然后添加到web流程中,代码如下:
- 拦截器实现
public class LoginAuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//这里实际是从redis中获取到session信息
HttpSession session = request.getSession();
Integer userId = (Integer) session.getAttribute("userId");
if (userId == null) {
authFailOutput(response, "登录信息不存在,请重新登录");
return false;
}
return true;
}
/**
* json输出
*
* @param response
* @throws IOException
*/
private void authFailOutput(HttpServletResponse response, String msg) throws IOException {
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
ObjectMapper objectMapper = new ObjectMapper();
out.write(objectMapper.writeValueAsString(CommonResVo.fail(400, msg)));
out.flush();
}
}
- 将自定义拦截器添加到web mvc中,这里可以添加多个拦截器,每个拦截器可以设置不同的拦截策略:
@Configuration
public class Interceptor implements WebMvcConfigurer {
@Bean
LoginAuthInterceptor loginAuthInterceptor() {
return new LoginAuthInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加一个拦截器,排除登录url
registry.addInterceptor(loginAuthInterceptor())
.excludePathPatterns("/user/login");
}
}
通常创建session后,sessionId会保存在cookies里面,默认名是SESSION,用于之后的每次请求。这里要注意,cookies保存的sessionId默认是base64编码过的,所以和程序中使用session.getId()
获取到的会不同。
3.1 自定义sessionId
如果不想使用系统默认的cookie名称保存sessionId,可以通过修改application.yml的配置实现自定名称,示例如下:
server:
port: 8999
servlet:
session:
cookie:
name: myjsessionid //自定义的session名称
这样系统中就会使用myjsessionid保存和解析session信息。
源码地址:https://gitee.com/dothetrick/web-demo/tree/register-login/
以上内容属个人学习总结,如有不当之处,欢迎在评论中指正
网友评论