07 登录接口开发
登录接口开发
登录的逻辑其实很简答,只需要接受账号密码,然后把用户的id生成jwt,返回给前段,为了后续的jwt的延期,所以我们把jwt放在header上。具体代码如下:
- com.gychen.controller.AccountController
@RestController
public class AccountController {
@Autowired
JwtUtils jwtUtils;
@Autowired
UserService userService;
/**
* 默认账号密码:gychen / 111111
*
*/
@CrossOrigin
@PostMapping("/login")
public Result login(@Validated @RequestBody LoginDto loginDto, HttpServletResponse response) {
User user = userService.getOne(new QueryWrapper<User>().eq("username", loginDto.getUsername()));
Assert.notNull(user, "用户不存在");
if(!user.getPassword().equals(SecureUtil.md5(loginDto.getPassword()))) {
return Result.fail("密码错误!");
}
String jwt = jwtUtils.generateToken(user.getId());
response.setHeader("Authorization", jwt);
response.setHeader("Access-Control-Expose-Headers", "Authorization");
// 用户可以另一个接口
return Result.succ(MapUtil.builder()
.put("id", user.getId())
.put("username", user.getUsername())
.put("avatar", user.getAvatar())
.put("email", user.getEmail())
.map()
);
}
// 退出
@GetMapping("/logout")
@RequiresAuthentication
public Result logout() {
SecurityUtils.getSubject().logout();
return Result.succ(null);
}
}
- 在postman软件里写接口请求测试
请求类型为POST,URL为http://localhost:8081/login,依次选择Body->raw->JSON
{
"_comment":"postman清求数据",
"username":"gychen",
"password":"111111"
}
{
"_comment":"服务器返回数据",
"code": "0",
"msg": "操作成功",
"data": {
"id": 1,
"avatar": "https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg",
"email": null,
"username": "gychen"
}
}
博客接口开发
我们的骨架已经完成,接下来,我们就可以添加我们的业务接口了,下面我以一个简单的博客列表、博客详情页为例子开发:
- com.gychen.controller.BlogController
package com.gychen.controller;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gychen.common.lang.Result;
import com.gychen.entity.Blog;
import com.gychen.service.BlogService;
import com.gychen.util.ShiroUtil;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
/**
* <p>
* 前端控制器
* </p>
*
* @author gychen
* @since 2020-07-28
*/
@RestController
public class BlogController {
@Autowired
BlogService blogService;
@GetMapping("/blogs")
public Result blogs(Integer currentPage) {
if(currentPage == null || currentPage < 1) currentPage = 1;
Page page = new Page(currentPage, 5);
IPage pageData = blogService.page(page, new QueryWrapper<Blog>().orderByDesc("created"));
return Result.succ(pageData);
}
@GetMapping("/blog/{id}")
public Result detail(@PathVariable(name = "id") Long id) {
Blog blog = blogService.getById(id);
Assert.notNull(blog, "该博客已删除!");
return Result.succ(blog);
}
@RequiresAuthentication // 此接口必须要通过登录认证才能访问
@PostMapping("/blog/edit")
public Result edit(@Validated @RequestBody Blog blog) {
System.out.println(blog.toString());
Blog temp = null;
if(blog.getId() != null) {
// 在数据库中查找传入id的博客存不存在
temp = blogService.getById(blog.getId());
// Assert.isTrue(temp.getUserId().longValue() == ShiroUtil.getProfile().getId().longValue(), "没有权限编辑");
Assert.isTrue(temp.getUserId().equals(ShiroUtil.getProfile().getId()), "没有权限编辑");
} else {
temp = new Blog();
temp.setUserId(ShiroUtil.getProfile().getId());
temp.setCreated(LocalDateTime.now());
temp.setStatus(0);
}
// 把blog复制到temp并忽略id、userId、created、status
BeanUtil.copyProperties(blog, temp, "id", "userId", "created", "status");
blogService.saveOrUpdate(temp);
return Result.succ(null);
}
}
- 在postman软件里写接口请求测试
-
先进行登录请求,登陆成功后在返回数据的请求头Headers里找到Authorization的value,复制value值
-
新建一个请求,请求类型为POST,URL为http://localhost:8081/blog/edit,在Headers里新建key:Authorization,value:复制的value值,依次选择Body->raw->JSON
-
测试代码
-
{ "title":"测试标题3333333333", "description":"description333333333", "content":"content33333333333" }
-
{ "title":"测试标题3333333333", "description":"description333333333" }
-
{ "id":11, "title":"测试标题3333333333", "description":"description333333333", "content":"content33333333333" }
-
{ "id":11, "title":"修改测试标题3333333333", "description":"description333333333", "content":"content1111111" }
-
-
暂时在这里出现了登录验证的问题,待解决
-
找了大概一个小时,在JwtFilter的onAcessDenied方法里发现发起请求时,后端根本在Header请求头里找不到jwt,后来发现原来是在postman里把token放Params里传给后端了。
-
测试结果
-
{ "code": "0", "msg": "操作成功", "data": null }
-
{ "code": "-1", "msg": "内容不能为空", "data": null }
-
{ "code": "0", "msg": "操作成功", "data": null }
-
{ "code": "0", "msg": "操作成功", "data": null }
-
注意@RequiresAuthentication说明需要登录之后才能访问的接口,其他需要权限的接口可以添加shiro的相关注解。 接口比较简单,我们就不多说了,基本增删改查而已。注意的是edit方法是需要登录才能操作的受限资源。