
⭐鉴权流程图:

orm框架:JPA
- @Table(name = "user_tab")
- @Entity
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class User implements Serializable {
-
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name="user_id")
- private Long id;
-
- @Column(name="user_name")
- private String username;
-
- @Column(name="user_password")
- private String password;
-
- @Column(name="user_phone")
- private String phone;
-
- @Column(name="user_nickname")
- private String nickname;
-
- @Column(name="user_create_by")
- private String createBy;
- @Column(name="user_create_time")
- private Date createTime;
- @Column(name="user_update_time")
- private Date updateTime;
-
- @Column(name="user_role_id")
- private Long roleId;
- }
- @Repository
- public interface UserDao extends JpaRepository
{ -
- //根据user的username和password查询该用户
- User findByUsernameAndPassword(String username,String password);
- }
- public interface UserService {
-
- //全查询
- List
findAllUsers(); -
- //1027-【从数据库读取用户名信息存入布隆过滤器中】
- void warnUpUsernames();
-
- //1027-【用户登录】
- User login(String username, String password);
-
- }
- @Service
- @Slf4j
- public class UserServiceImpl implements UserService {
-
- @Autowired
- private UserDao userDao;
- @Autowired
- private StringRedisTemplate stringRedisTemplate;
-
- //全查询
- @Override
- public List
findAllUsers() { - return userDao.findAll();
- }
-
- //1027-【从数据库读取用户名信息存入布隆过滤器中】
- @Override
- public void warnUpUsernames() {
- userDao.findAll().forEach(u -> {
- stringRedisTemplate.opsForValue()
- .getOperations()
- .execute(new DefaultRedisScript
( - "return redis.call('bf.add',KEYS[1],ARGV[1])"
- , Long.class),
- new ArrayList
() {{ - add("whiteUsernames");
- }}, u.getUsername()
- );
- }
- );
- }
-
- //1027-【用户登录】
- @Override
- public User login(String username, String password) {
- if(!StringUtils.hasText(username)){
- throw new UsernameIsEmptyException("用户名为空异常");
- }
- username = username.trim();
- if(checkFromWhite(username)){
- throw new UsernameNotFoundException("用户名不存在异常");
- }
-
- User user = userDao.findByUsernameAndPassword(username, password);
-
- if(Objects.isNull(user)){
- throw new BadCredentialsException("用户名|密码错误");
- }
-
- return user;
- }
-
- //判断用户名是否存在于布隆过滤器
- private boolean checkFromWhite(String username) {
- Long isExist = stringRedisTemplate.opsForValue()
- .getOperations()
- .execute(new DefaultRedisScript
("return redis.call('bf.exists',KEYS[1],ARGV[1])", Long.class), - new ArrayList
() {{ - add("whiteUsernames");
- }}, username);
-
- return isExist.intValue() == 0;
- }
- @Api(tags = "用户模块接口")
- @RestController
- @RequestMapping("/api/user")
- @Slf4j
- public class UserController {
-
- @Autowired
- private UserService userService;
- @Autowired
- private StringRedisTemplate stringRedisTemplate;
-
-
- //1027-【全查询】
- @ApiOperation(value = "findAllUsers",notes = "查询所有用户,需要当前用户登录状态")
- @GetMapping("/findAllUsers")
- @BmsRole(value="1")
- public HttpResp
> findAllUsers(){
- return HttpResp.success(userService.findAllUsers());
- }
-
-
- //1027-【用户登录】
- @ApiOperation(value = "login",notes = "用户登录")
- @GetMapping("login")
- public HttpResp login(HttpServletResponse response, String username, String password){
- //首先调用AuthorityService的login方法进行用户登录验证,返回一个User对象。
- User user = userService.login(username,password);
-
- //然后生成一个JWT作为用户的身份认证凭证,其中包含了用户名和过期时间等信息。
- //使用JWT.create()创建JWT对象,并使用withClaim()方法设置用户名,withExpiresAt()方法设置过期时间。
- String salt = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8));
-
-
- log.debug("user:{}",user);
- String token = JWT.create()
- .withClaim("username", username)
- .withClaim("roleId",""+user.getRoleId())
- .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 30)) //30分钟令牌过期
- .sign(Algorithm.HMAC256(salt)); //使用Algorithm.HMAC256(salt)指定加密算法和密钥,对JWT进行签名。
- log.debug("用户验证通过,生成token为:{}",token);
-
- //将生成的JWT存储到Redis缓存中,使用stringRedisTemplate.opsForValue().set()方法设置键值对,并使用stringRedisTemplate.expire()方法设置过期时间
- stringRedisTemplate.opsForValue().set(token,salt);
- stringRedisTemplate.expire(token,60, TimeUnit.MINUTES); //60分钟redis缓存token过期
- response.addCookie(new Cookie("token",token)); //将JWT作为Cookie添加到HTTP响应中,使用response.addCookie()方法
-
- return HttpResp.success(user); //最后返回一个成功的响应,消息体中包含了登录成功的用户对象
- }
-
- }
- @Configuration
- @Slf4j
- public class BmsMvcConfig implements WebMvcConfigurer {
-
- @Bean
- public AuthorityInterceptor authorityInterceptor(){
- log.debug("BmsMvc拦截器启动成功:{}..........",new Date());
- return new AuthorityInterceptor();
- }
-
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(authorityInterceptor())
- .addPathPatterns("/api/**")
- .excludePathPatterns(
- "/api/user/login"
- );
- }
- }
- @Slf4j
- public class AuthorityInterceptor implements HandlerInterceptor {
-
- @Autowired
- private StringRedisTemplate stringRedisTemplate;
-
- /**
- *
- * @param request
- * @param response
- * @param handler 当前拦截器拦截的方法
- * @return
- * @throws Exception
- */
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- log.debug("已进入拦截器:{}",new Date());
-
- String token = request.getHeader("token");
-
- //1.从redis中读取token,如果不存在,则用户是非法用户,抛出自定义异常类InvalidTokenException
- Boolean isRedis = stringRedisTemplate.hasKey(token);
-
- if(!isRedis) throw new InvalidTokenException("无效的token");
-
- String salt = stringRedisTemplate.opsForValue().get(token);
- log.debug("salt:{}",salt);
- DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(salt)).build().verify(token);
-
- //2.token验证完成正确
- String roleId = decodedJWT.getClaim("roleId").asString();
- log.debug("------->roleId:{}",roleId);
-
- HandlerMethod method = (HandlerMethod) handler;
- //System.out.println("----->"+method.getMethod().getDeclaredAnnotation(GetMapping.class));
- BmsRole bmsRole= method.getMethod().getDeclaredAnnotation(BmsRole.class);
- String requiredRolId = bmsRole.value();
-
- if(!roleId.equals(requiredRolId)){
- throw new PermissionDeniedException("您没有足够的权限");
- }
-
- //获取请求对象的角色名称
- //获取请求的地址(uri)
- // String requestURI = request.getRequestURI();
- // requestURI = requestURI.substring(requestURI.lastIndexOf("/") + 1);
- // log.debug("请求路径uri:{}",requestURI);//URL/URI
- // System.out.println(handler.getClass());
-
- return HandlerInterceptor.super.preHandle(request, response, handler);
- }
- }
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.****.bms.authority.config.BmsMvcConfig,com.****.bms.authority.handler.UserExceptionHandler
未完待续......