需要的工具类,请前往:https://cloud.tencent.com/developer/article/2311121
本文章是使用方法,数据库查询使用的是mybatis-plus
mybatis-plus依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</dependency>
为什么mybatis-plus依赖要在这里写?
因为:
注意:我的包名叫com.zb,凡是报错的类,记得把包换成你的包
1.UserService里面有一个方法:根据用户名和密码查询,返回token
注意:不要想着直接写自已登录的Service里面,不行,因为下面要实现一个类叫UserDetailsService,你自已登录的Service里面无法同时实现2个
String login(String username, String passwd);
2.UserDetailServiceImpl继承UserDetailsService
实现public UserDetails loadUserByUsername方法,Security会自动找谁实现了,然后获取信息,注意看注释
代码:
package com.zb.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zb.entity.LoginUser;
import com.zb.entity.Menu;
import com.zb.entity.User;
import com.zb.mapper.MenuMapper;
import com.zb.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
//权限认证表,不需要权限直接删除即可
@Autowired
private MenuMapper menuMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("2.进入访问数据库的UserDetailServiceImpl服务类中...");
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("nick_name", username);
//根据用户名查询用户信息
User user = userMapper.selectOne(queryWrapper);
//权限认证,如不需要权限搞权限,直接删除即可
//拿用户名 查用户权限等信息
List<Menu> query = menuMapper.query(user.getId().toString());
//读取query里面权限信息(Perms参数),将信息存入list
List<String> list = query.stream().map(menu -> {
return menu.getPerms();
}).collect(Collectors.toList());
//权限认证,如不需要权限搞权限,删到这里
if (user != null) {
//将用户信息,权限信息放入LoginUser
//如不要权限认证,要把下面list参数删除
//然后去LoginUser类,24行和31行,删的东西如下:
//LoginUser(AdminEntity user, List<String> powers)方法,删除List<String> powers参数
//Collection<? extends GrantedAuthority> getAuthorities()直接把这个方法返回null即可
return new LoginUser(user, list);
}
return null;
}
}
3.UserServiceImpl继承自已的UserService,实现自已的login方法
注意:看42-45行
package com.zb.service.impl;
import com.alibaba.fastjson.JSON;
import com.zb.config.JwtUtil;
import com.zb.entity.LoginUser;
import com.zb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
//发起验证,此方法已经实例化
private AuthenticationManager authenticationManager;
@Override
public String login(String username, String passwd) {
//使用密码器,并且告诉密码器登录的账号密码
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(username, passwd);
//告诉验证起,本次登录使用的是密码器验证
//这里会调用:实现UserDetailsService接口的UserDetails类 loadUserByUsername的方法
//本意就是已经查出数据了
Authentication authenticate = authenticationManager
.authenticate(usernamePasswordAuthenticationToken);
if (ObjectUtils.isEmpty(authenticate)) {
return "登陆失败";
}
System.out.println("3.登陆成功信息");
//获取数据,转成LoginUser对象
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
//拿出用户名,生成token
String token = JwtUtil.createJWT(loginUser.getUser().getNickName());
//将用户名和用户信息存入redis
redisTemplate.boundValueOps("token:" + loginUser.getUser().getNickName()).set(JSON.toJSONString(loginUser));
return token;
}
}
4.Controller实现刚开始创建UserService方法即可,它会返回一个token,普通方法必须传入token,否则会被拦截
package com.zb.controller;
import com.zb.entity.LoginUser;
import com.zb.entity.User;
import com.zb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private RedisTemplate redisTemplate;
@PostMapping("/login")
public String login(@RequestParam("username") String username, @RequestParam("passwd") String passwd) {
return userService.login(username, passwd);
}
@GetMapping("/info")
public User info() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
return loginUser.getUser();
}
@GetMapping("/exit")
public String exit() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
String key = "token:" + loginUser.getUser().getNickName();
redisTemplate.delete(key);
return "success";
}
@GetMapping("/testok")
public String tsetok(@RequestHeader String token){
System.out.println("这是一个普通方法");
return "这是一个普通方法";
}
}
5.权限拦截,使用@PreAuthorize(“”)注解,里面填的是存放LoginUser类里面查出来的powers权限名字
如果不要权限认证,这里就不用看了
package com.zb.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/show")
@PreAuthorize("hasAuthority('book:search') or hasAuthority('book:get')")
public String show() {
System.out.println("============>");
return "hello";
}
}