Commit 0edcf9b6 by giaogiao

shiro改造:能识别app用户权限, 能识别平台系统权限,

未完成商户平台权限
parent 7c5894bd
...@@ -6,6 +6,7 @@ import io.geekidea.springbootplus.framework.log.annotation.OperationLog; ...@@ -6,6 +6,7 @@ import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
...@@ -31,7 +32,7 @@ public class AppHelloWorldController { ...@@ -31,7 +32,7 @@ public class AppHelloWorldController {
*/ */
@GetMapping(value = "/world") @GetMapping(value = "/world")
@OperationLog(name = "helloWorld") @OperationLog(name = "helloWorld")
@ApiOperation(value = "Hello World", response = String.class) @ApiOperation(value = "helloWorld", response = String.class)
public ApiResult<String> helloWorld() throws IOException { public ApiResult<String> helloWorld() throws IOException {
log.debug("Hello World...app"); log.debug("Hello World...app");
return ApiResult.ok("Hello World app"); return ApiResult.ok("Hello World app");
...@@ -40,15 +41,32 @@ public class AppHelloWorldController { ...@@ -40,15 +41,32 @@ public class AppHelloWorldController {
@GetMapping(value = "/needRole") @GetMapping(value = "/needRole")
@OperationLog(name = "needRole") @OperationLog(name = "needRole")
@ApiOperation(value = "Hello World", response = String.class) @ApiOperation(value = "needRole", response = String.class)
public ApiResult<String> needRole() throws IOException { public ApiResult<String> needRole() throws IOException {
log.debug("Hello World...app"); log.debug("Hello World...app");
return ApiResult.ok("Hello World app"); return ApiResult.ok("Hello World app");
} }
@GetMapping(value = "/needRoleAdmin")
@OperationLog(name = "needRoleAdmin")
@ApiOperation(value = "needRoleAdmin", response = String.class)
@RequiresRoles("app:admin")
public ApiResult<String> needRoleAdmin() throws IOException {
log.debug("Hello World...app");
return ApiResult.ok("Hello World needRoleAdmin");
}
@GetMapping(value = "/needRoleAll")
@OperationLog(name = "needRoleAll")
@ApiOperation(value = "needRoleAll", response = String.class)
@RequiresRoles("app:all")
public ApiResult<String> needRoleAll() throws IOException {
log.debug("Hello World...app");
return ApiResult.ok("Hello World needRoleAll");
}
@GetMapping(value = "/noRole") @GetMapping(value = "/noRole")
@OperationLog(name = "noRole") @OperationLog(name = "noRole")
@ApiOperation(value = "Hello World", response = String.class) @ApiOperation(value = "noRole", response = String.class)
public ApiResult<String> noRole() throws IOException { public ApiResult<String> noRole() throws IOException {
log.debug("Hello World...app"); log.debug("Hello World...app");
return ApiResult.ok("Hello World app noRole"); return ApiResult.ok("Hello World app noRole");
......
...@@ -2,6 +2,7 @@ package com.jumeirah.api.app.controller; ...@@ -2,6 +2,7 @@ package com.jumeirah.api.app.controller;
import com.jumeirah.common.entity.AppUser; import com.jumeirah.common.entity.AppUser;
import com.jumeirah.common.param.AppUserPageParam; import com.jumeirah.common.param.AppUserPageParam;
import com.jumeirah.common.param.LoginParam;
import com.jumeirah.common.param.RegisterParam; import com.jumeirah.common.param.RegisterParam;
import com.jumeirah.common.service.AppUserService; import com.jumeirah.common.service.AppUserService;
import com.jumeirah.common.vo.AppUserQueryVo; import com.jumeirah.common.vo.AppUserQueryVo;
...@@ -106,14 +107,20 @@ public class AppUserController extends BaseController { ...@@ -106,14 +107,20 @@ public class AppUserController extends BaseController {
@ApiOperation(value = "注册", notes = "web用户注册", response = LoginSysUserTokenVo.class) @ApiOperation(value = "注册", notes = "web用户注册", response = LoginSysUserTokenVo.class)
public ApiResult<LoginSysUserTokenVo> register(@Validated @RequestBody RegisterParam registerParam, HttpServletResponse response, @RequestHeader(required = false) String language) throws Exception { public ApiResult<LoginSysUserTokenVo> register(@Validated @RequestBody RegisterParam registerParam, HttpServletResponse response, @RequestHeader(required = false) String language) throws Exception {
return appUserService.register(registerParam, language); return appUserService.register(registerParam, language);
} }
@PostMapping("/phoneLogin") @PostMapping("/login")
@OperationLogIgnore @OperationLogIgnore
@ApiOperation(value = "手机号登陆", notes = "手机号登陆", response = LoginSysUserTokenVo.class) @ApiOperation(value = "登录", notes = "系统用户登录", response = LoginSysUserTokenVo.class)
public ApiResult<LoginSysUserTokenVo> phoneLogin(@Validated @RequestBody RegisterParam registerParam, HttpServletResponse response, @RequestHeader(required = false) String language) throws Exception { public ApiResult<LoginSysUserTokenVo> login(@Validated @RequestBody LoginParam loginParam, HttpServletResponse response, @RequestHeader(required = false) String language) throws Exception {
return appUserService.register(registerParam, language); return appUserService.login(loginParam, language);
} }
// @PostMapping("/phoneLogin")
// @OperationLogIgnore
// @ApiOperation(value = "手机号登陆", notes = "手机号登陆", response = LoginSysUserTokenVo.class)
// public ApiResult<LoginSysUserTokenVo> phoneLogin(@Validated @RequestBody RegisterParam registerParam, HttpServletResponse response, @RequestHeader(required = false) String language) throws Exception {
// return appUserService.register(registerParam, language);
// }
} }
...@@ -56,6 +56,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties ...@@ -56,6 +56,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.filter.DelegatingFilterProxy; import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
...@@ -203,13 +204,14 @@ public class ShiroConfig { ...@@ -203,13 +204,14 @@ public class ShiroConfig {
ShiroLoginService shiroLoginService, ShiroLoginService shiroLoginService,
SysLoginRedisService sysLoginRedisService, SysLoginRedisService sysLoginRedisService,
ShiroProperties shiroProperties, ShiroProperties shiroProperties,
JwtProperties jwtProperties) { JwtProperties jwtProperties,
RedisTemplate redisTemplate) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器 // 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置过滤器 // 设置过滤器
Map<String, Filter> filterMap = getFilterMap(shiroLoginService, sysLoginRedisService, jwtProperties); Map<String, Filter> filterMap = getFilterMap(shiroLoginService, sysLoginRedisService, jwtProperties,redisTemplate);
shiroFilterFactoryBean.setFilters(filterMap); shiroFilterFactoryBean.setFilters(filterMap);
// 设置过滤器顺序 // 设置过滤器顺序
Map<String, String> filterChainMap = getFilterChainDefinitionMap(shiroProperties); Map<String, String> filterChainMap = getFilterChainDefinitionMap(shiroProperties);
...@@ -225,9 +227,10 @@ public class ShiroConfig { ...@@ -225,9 +227,10 @@ public class ShiroConfig {
*/ */
private Map<String, Filter> getFilterMap(ShiroLoginService shiroLoginService, private Map<String, Filter> getFilterMap(ShiroLoginService shiroLoginService,
SysLoginRedisService loginRedisService, SysLoginRedisService loginRedisService,
JwtProperties jwtProperties) { JwtProperties jwtProperties,
RedisTemplate redisTemplate) {
Map<String, Filter> filterMap = new LinkedHashMap<>(); Map<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put(JWT_FILTER_NAME, new JwtFilter(shiroLoginService, loginRedisService, jwtProperties)); filterMap.put(JWT_FILTER_NAME, new JwtFilter(shiroLoginService, loginRedisService, jwtProperties, redisTemplate));
return filterMap; return filterMap;
} }
......
...@@ -2,6 +2,7 @@ package com.jumeirah.common.service; ...@@ -2,6 +2,7 @@ package com.jumeirah.common.service;
import com.jumeirah.common.entity.AppUser; import com.jumeirah.common.entity.AppUser;
import com.jumeirah.common.param.AppUserPageParam; import com.jumeirah.common.param.AppUserPageParam;
import com.jumeirah.common.param.LoginParam;
import com.jumeirah.common.param.RegisterParam; import com.jumeirah.common.param.RegisterParam;
import com.jumeirah.common.vo.AppUserQueryVo; import com.jumeirah.common.vo.AppUserQueryVo;
import com.jumeirah.common.vo.LoginSysUserTokenVo; import com.jumeirah.common.vo.LoginSysUserTokenVo;
...@@ -18,6 +19,8 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging; ...@@ -18,6 +19,8 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging;
public interface AppUserService extends BaseService<AppUser> { public interface AppUserService extends BaseService<AppUser> {
ApiResult<LoginSysUserTokenVo> register(RegisterParam registerParam, String language); ApiResult<LoginSysUserTokenVo> register(RegisterParam registerParam, String language);
ApiResult<LoginSysUserTokenVo> login(LoginParam loginParam, String language);
ApiResult<LoginSysUserTokenVo> phoneLogin(RegisterParam registerParam, String language); ApiResult<LoginSysUserTokenVo> phoneLogin(RegisterParam registerParam, String language);
......
package com.jumeirah.common.service.impl; package com.jumeirah.common.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jumeirah.common.entity.AppUser; import com.jumeirah.common.entity.AppUser;
import com.jumeirah.common.enums.StateEnum;
import com.jumeirah.common.mapper.AppUserMapper; import com.jumeirah.common.mapper.AppUserMapper;
import com.jumeirah.common.param.AppUserPageParam; import com.jumeirah.common.param.AppUserPageParam;
import com.jumeirah.common.param.LoginParam;
import com.jumeirah.common.param.RegisterParam; import com.jumeirah.common.param.RegisterParam;
import com.jumeirah.common.service.AppUserService; import com.jumeirah.common.service.AppUserService;
import com.jumeirah.common.vo.AppUserQueryVo; import com.jumeirah.common.vo.AppUserQueryVo;
import com.jumeirah.common.vo.LoginSysUserTokenVo; import com.jumeirah.common.vo.LoginSysUserTokenVo;
import io.geekidea.springbootplus.config.properties.JwtProperties;
import io.geekidea.springbootplus.config.properties.SpringBootPlusProperties;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl; import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo; import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.shiro.cache.AppLoginRedisService;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import io.geekidea.springbootplus.framework.shiro.util.SaltUtil;
import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserVo;
import io.geekidea.springbootplus.framework.util.PasswordUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
/** /**
* APP用户 服务实现类 * APP用户 服务实现类
* *
...@@ -30,6 +51,20 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -30,6 +51,20 @@ import org.springframework.transaction.annotation.Transactional;
public class AppUserServiceImpl extends BaseServiceImpl<AppUserMapper, AppUser> implements AppUserService { public class AppUserServiceImpl extends BaseServiceImpl<AppUserMapper, AppUser> implements AppUserService {
@Autowired @Autowired
private RedisTemplate redisTemplate;
@Lazy
@Autowired
private AppLoginRedisService appLoginRedisService;
@Lazy
@Autowired
private JwtProperties jwtProperties;
@Autowired
private SpringBootPlusProperties springBootPlusProperties;
@Autowired
private AppUserMapper appUserMapper; private AppUserMapper appUserMapper;
@Override @Override
...@@ -38,6 +73,83 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserMapper, AppUser> ...@@ -38,6 +73,83 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserMapper, AppUser>
} }
@Override @Override
public ApiResult<LoginSysUserTokenVo> login(LoginParam loginParam, String language) {
// 校验验证码
// checkVerifyCode(loginParam.getVerifyToken(), loginParam.getCode());
String username = loginParam.getUsername();
// 从数据库中获取登录用户信息
AppUser appUser = appUserMapper.selectOne(new QueryWrapper<AppUser>(new AppUser().setUsername(username)));
if (appUser == null) {
log.error("登录失败,loginParam:{}", loginParam);
// throw new AuthenticationException("用户名或密码错误");
return ApiResult.fail(ApiCode.PWD_OR_USERNAME_ERROR, language);
}
if (StateEnum.DISABLE.getCode().equals(appUser.getState())) {
throw new AuthenticationException("账号已禁用");
}
// 实际项目中,前端传过来的密码应先加密
// 原始密码明文:123456
// 原始密码前端加密:sha256(123456)
// 后台加密规则:sha256(sha256(123456) + salt)
String encryptPassword = PasswordUtil.encrypt(loginParam.getPassword(), appUser.getSalt());
if (!encryptPassword.equals(appUser.getPassword())) {
return ApiResult.fail(ApiCode.PWD_OR_USERNAME_ERROR, language);
}
// 将系统用户对象转换成登录用户对象
LoginSysUserVo loginSysUserVo = new LoginSysUserVo();
loginSysUserVo.setUsername(username);
// 获取数据库中保存的盐值
String newSalt = SaltUtil.getSalt(appUser.getSalt(), jwtProperties);
// 生成token字符串并返回
Long expireSecond = jwtProperties.getExpireSecond();
String token = JwtUtil.generateToken(username, newSalt, Duration.ofSeconds(expireSecond));
log.debug("token:{}", token);
// 创建AuthenticationToken
JwtToken jwtToken = JwtToken.build(token, username, newSalt, expireSecond,"app");
boolean enableShiro = springBootPlusProperties.getShiro().isEnable();
if (enableShiro) {
// 从SecurityUtils里边创建一个 subject
Subject subject = SecurityUtils.getSubject();
// 执行认证登录
subject.login(jwtToken);
} else {
log.warn("未启用Shiro");
}
// 缓存登录信息到Redis
appLoginRedisService.cacheLoginInfo(jwtToken, loginSysUserVo);
log.debug("登录成功,username:{}", username);
// 缓存登录信息到redis
String tokenSha256 = DigestUtils.sha256Hex(token);
redisTemplate.opsForValue().set(tokenSha256, loginSysUserVo, 1, TimeUnit.DAYS);
// 返回token和登录用户信息对象
LoginSysUserTokenVo loginSysUserTokenVo = new LoginSysUserTokenVo();
loginSysUserTokenVo.setToken(token);
loginSysUserTokenVo.setLoginSysUserVo(loginSysUserVo);
// 设置token响应头
// response.setHeader(JwtTokenUtil.getTokenName(), loginSysUserTokenVo.getToken());
return ApiResult.ok(loginSysUserTokenVo, language);
}
@Override
public ApiResult<LoginSysUserTokenVo> phoneLogin(RegisterParam registerParam, String language) { public ApiResult<LoginSysUserTokenVo> phoneLogin(RegisterParam registerParam, String language) {
return null; return null;
} }
......
...@@ -22,8 +22,13 @@ import com.jumeirah.common.entity.SysDepartment; ...@@ -22,8 +22,13 @@ import com.jumeirah.common.entity.SysDepartment;
import com.jumeirah.common.entity.SysRole; import com.jumeirah.common.entity.SysRole;
import com.jumeirah.common.entity.SysUser; import com.jumeirah.common.entity.SysUser;
import com.jumeirah.common.enums.StateEnum; import com.jumeirah.common.enums.StateEnum;
import com.jumeirah.common.exception.VerificationCodeException;
import com.jumeirah.common.mapper.SysUserMapper; import com.jumeirah.common.mapper.SysUserMapper;
import com.jumeirah.common.param.LoginParam; import com.jumeirah.common.param.LoginParam;
import com.jumeirah.common.service.SysDepartmentService;
import com.jumeirah.common.service.SysLoginService;
import com.jumeirah.common.service.SysRolePermissionService;
import com.jumeirah.common.service.SysRoleService;
import com.jumeirah.common.vo.LoginSysUserTokenVo; import com.jumeirah.common.vo.LoginSysUserTokenVo;
import io.geekidea.springbootplus.config.constant.CommonRedisKey; import io.geekidea.springbootplus.config.constant.CommonRedisKey;
import io.geekidea.springbootplus.config.properties.JwtProperties; import io.geekidea.springbootplus.config.properties.JwtProperties;
...@@ -37,11 +42,6 @@ import io.geekidea.springbootplus.framework.shiro.util.JwtUtil; ...@@ -37,11 +42,6 @@ import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import io.geekidea.springbootplus.framework.shiro.util.SaltUtil; import io.geekidea.springbootplus.framework.shiro.util.SaltUtil;
import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserVo; import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserVo;
import io.geekidea.springbootplus.framework.util.PasswordUtil; import io.geekidea.springbootplus.framework.util.PasswordUtil;
import com.jumeirah.common.exception.VerificationCodeException;
import com.jumeirah.common.service.SysLoginService;
import com.jumeirah.common.service.SysDepartmentService;
import com.jumeirah.common.service.SysRolePermissionService;
import com.jumeirah.common.service.SysRoleService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
...@@ -61,8 +61,6 @@ import java.time.Duration; ...@@ -61,8 +61,6 @@ import java.time.Duration;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static io.geekidea.springbootplus.framework.common.api.ApiResult.fail;
/** /**
* <p> * <p>
* 登录服务实现类 * 登录服务实现类
...@@ -180,7 +178,7 @@ public class SysLoginServiceImpl implements SysLoginService { ...@@ -180,7 +178,7 @@ public class SysLoginServiceImpl implements SysLoginService {
log.debug("token:{}", token); log.debug("token:{}", token);
// 创建AuthenticationToken // 创建AuthenticationToken
JwtToken jwtToken = JwtToken.build(token, username, newSalt, expireSecond); JwtToken jwtToken = JwtToken.build(token, username, newSalt, expireSecond,"sys");
boolean enableShiro = springBootPlusProperties.getShiro().isEnable(); boolean enableShiro = springBootPlusProperties.getShiro().isEnable();
if (enableShiro) { if (enableShiro) {
......
...@@ -30,7 +30,7 @@ public interface AppLoginRedisKey { ...@@ -30,7 +30,7 @@ public interface AppLoginRedisKey {
* 登录用户token信息key * 登录用户token信息key
* login:token:tokenMd5 * login:token:tokenMd5
*/ */
String LOGIN_TOKEN = "app:login:token:%s"; String LOGIN_TOKEN = "sys:login:token:%s";
/** /**
* 登录用户信息key * 登录用户信息key
...@@ -42,7 +42,9 @@ public interface AppLoginRedisKey { ...@@ -42,7 +42,9 @@ public interface AppLoginRedisKey {
* 登录用户盐值信息key * 登录用户盐值信息key
* login:salt:username * login:salt:username
*/ */
String LOGIN_SALT = "app:login:salt:%s"; // String LOGIN_SALT = "app:login:salt:%s";
String LOGIN_SALT = "sys:login:salt:%s";
/** /**
* 登录用户username token * 登录用户username token
......
...@@ -30,7 +30,7 @@ public interface MerchantLoginRedisKey { ...@@ -30,7 +30,7 @@ public interface MerchantLoginRedisKey {
* 登录用户token信息key * 登录用户token信息key
* login:token:tokenMd5 * login:token:tokenMd5
*/ */
String LOGIN_TOKEN = "mer:login:token:%s"; String LOGIN_TOKEN = "sys:login:token:%s";
/** /**
* 登录用户信息key * 登录用户信息key
...@@ -42,7 +42,7 @@ public interface MerchantLoginRedisKey { ...@@ -42,7 +42,7 @@ public interface MerchantLoginRedisKey {
* 登录用户盐值信息key * 登录用户盐值信息key
* login:salt:username * login:salt:username
*/ */
String LOGIN_SALT = "mer:login:salt:%s"; String LOGIN_SALT = "sys:login:salt:%s";
/** /**
* 登录用户username token * 登录用户username token
......
...@@ -7,7 +7,7 @@ server: ...@@ -7,7 +7,7 @@ server:
context-path: /api context-path: /api
tomcat: tomcat:
max-threads: 200 max-threads: 200
min-spare-threads: 10 min-spare-threads: 5
uri-encoding: UTF-8 uri-encoding: UTF-8
############################# 访问路径、端口tomcat end ############################### ############################# 访问路径、端口tomcat end ###############################
...@@ -183,7 +183,7 @@ spring-boot-plus: ...@@ -183,7 +183,7 @@ spring-boot-plus:
# 权限配置 # 权限配置
anon: anon:
# 排除登录 注册 登出 # 排除登录 注册 登出
- /app/user/register,/app/user/phoneLogin,/sys/login,/sys/logout,/sys/register - /app/user/register,/app/user/phoneLogin,/app/user/login,/sys/login,/sys/logout,/sys/register
# 排除静态资源 # 排除静态资源
- /static/**,/templates/** - /static/**,/templates/**
# 排除Swagger # 排除Swagger
...@@ -200,7 +200,7 @@ spring-boot-plus: ...@@ -200,7 +200,7 @@ spring-boot-plus:
/upload/**=anon /upload/**=anon
/verificationCode/**=anon /verificationCode/**=anon
/enum=anon /enum=anon
# /app/**=authc /app/*=roles["app:all"]
######################## Spring Shiro end ########################## ######################## Spring Shiro end ##########################
......
...@@ -47,6 +47,7 @@ public class AppLoginRedisServiceImpl implements AppLoginRedisService { ...@@ -47,6 +47,7 @@ public class AppLoginRedisServiceImpl implements AppLoginRedisService {
if (loginSysUserVo == null) { if (loginSysUserVo == null) {
throw new IllegalArgumentException("loginSysUserVo不能为空"); throw new IllegalArgumentException("loginSysUserVo不能为空");
} }
// token // token
String token = jwtToken.getToken(); String token = jwtToken.getToken();
// 盐值 // 盐值
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package io.geekidea.springbootplus.framework.shiro.jwt; package io.geekidea.springbootplus.framework.shiro.jwt;
import io.geekidea.springbootplus.config.constant.SysLoginRedisKey;
import io.geekidea.springbootplus.config.properties.JwtProperties; import io.geekidea.springbootplus.config.properties.JwtProperties;
import io.geekidea.springbootplus.framework.common.api.ApiCode; import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
...@@ -23,14 +24,17 @@ import io.geekidea.springbootplus.framework.shiro.cache.SysLoginRedisService; ...@@ -23,14 +24,17 @@ import io.geekidea.springbootplus.framework.shiro.cache.SysLoginRedisService;
import io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService; import io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService;
import io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil; import io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil; import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import io.geekidea.springbootplus.framework.shiro.vo.JwtTokenRedisVo;
import io.geekidea.springbootplus.framework.util.HttpServletResponseUtil; import io.geekidea.springbootplus.framework.util.HttpServletResponseUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter; import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils; import org.apache.shiro.web.util.WebUtils;
import org.springframework.data.redis.core.RedisTemplate;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
...@@ -47,16 +51,19 @@ import javax.servlet.http.HttpServletResponse; ...@@ -47,16 +51,19 @@ import javax.servlet.http.HttpServletResponse;
@Slf4j @Slf4j
public class JwtFilter extends AuthenticatingFilter { public class JwtFilter extends AuthenticatingFilter {
private RedisTemplate redisTemplate;
private final ShiroLoginService shiroLoginService; private final ShiroLoginService shiroLoginService;
private final SysLoginRedisService loginRedisService; private final SysLoginRedisService sysLoginRedisService;
private final JwtProperties jwtProperties; private final JwtProperties jwtProperties;
public JwtFilter(ShiroLoginService shiroLoginService, SysLoginRedisService loginRedisService, JwtProperties jwtProperties) { public JwtFilter(ShiroLoginService shiroLoginService, SysLoginRedisService loginRedisService, JwtProperties jwtProperties, RedisTemplate redisTemplate) {
this.shiroLoginService = shiroLoginService; this.shiroLoginService = shiroLoginService;
this.loginRedisService = loginRedisService; this.sysLoginRedisService = loginRedisService;
this.jwtProperties = jwtProperties; this.jwtProperties = jwtProperties;
this.redisTemplate = redisTemplate;
} }
/** /**
...@@ -77,22 +84,29 @@ public class JwtFilter extends AuthenticatingFilter { ...@@ -77,22 +84,29 @@ public class JwtFilter extends AuthenticatingFilter {
throw new AuthenticationException("JWT Token已过期,token:" + token); throw new AuthenticationException("JWT Token已过期,token:" + token);
} }
Object jwtTokenRedisVo = null;
// 如果开启redis二次校验,或者设置为单个用户token登录,则先在redis中判断token是否存在 // 如果开启redis二次校验,或者设置为单个用户token登录,则先在redis中判断token是否存在
if (jwtProperties.isRedisCheck() || jwtProperties.isSingleLogin()) { if (jwtProperties.isRedisCheck() || jwtProperties.isSingleLogin()) {
boolean redisExpired = loginRedisService.exists(token); String tokenMd5 = DigestUtils.md5Hex(token);
if (!redisExpired) { jwtTokenRedisVo = redisTemplate.opsForValue().get(String.format(SysLoginRedisKey.LOGIN_TOKEN, tokenMd5));
// boolean redisExpired = sysLoginRedisService.exists(token);
if (jwtTokenRedisVo == null) {
throw new AuthenticationException("Redis Token不存在,token:" + token); throw new AuthenticationException("Redis Token不存在,token:" + token);
} }
} }
String username = JwtUtil.getUsername(token); String username = JwtUtil.getUsername(token);
String salt; String salt;
if (jwtProperties.isSaltCheck()) { if (jwtProperties.isSaltCheck()) {
salt = loginRedisService.getSalt(username); salt = sysLoginRedisService.getSalt(username);
} else { } else {
salt = jwtProperties.getSecret(); salt = jwtProperties.getSecret();
} }
return JwtToken.build(token, username, salt, jwtProperties.getExpireSecond()); JwtTokenRedisVo jwt = (JwtTokenRedisVo) jwtTokenRedisVo;
return JwtToken.build(token, username, salt, jwtProperties.getExpireSecond(), jwt.getType());
} }
/** /**
...@@ -118,6 +132,7 @@ public class JwtFilter extends AuthenticatingFilter { ...@@ -118,6 +132,7 @@ public class JwtFilter extends AuthenticatingFilter {
} }
/** /**
* 执行登陆认证
* 判断是否允许访问 * 判断是否允许访问
* *
* @param request * @param request
......
...@@ -37,6 +37,8 @@ import java.util.Date; ...@@ -37,6 +37,8 @@ import java.util.Date;
public class JwtToken implements HostAuthenticationToken { public class JwtToken implements HostAuthenticationToken {
private static final long serialVersionUID = 5101247566043093405L; private static final long serialVersionUID = 5101247566043093405L;
private String type;
/** /**
* 登录ip * 登录ip
*/ */
...@@ -70,7 +72,7 @@ public class JwtToken implements HostAuthenticationToken { ...@@ -70,7 +72,7 @@ public class JwtToken implements HostAuthenticationToken {
private String credentials; private String credentials;
public static JwtToken build(String token, String username, String salt, long expireSecond) { public static JwtToken build(String token, String username, String salt, long expireSecond,String type) {
DecodedJWT decodedJwt = JwtUtil.getJwtInfo(token); DecodedJWT decodedJwt = JwtUtil.getJwtInfo(token);
Date createDate = decodedJwt.getIssuedAt(); Date createDate = decodedJwt.getIssuedAt();
Date expireDate = decodedJwt.getExpiresAt(); Date expireDate = decodedJwt.getExpiresAt();
...@@ -79,6 +81,7 @@ public class JwtToken implements HostAuthenticationToken { ...@@ -79,6 +81,7 @@ public class JwtToken implements HostAuthenticationToken {
.setToken(token) .setToken(token)
.setHost(IpUtil.getRequestIp()) .setHost(IpUtil.getRequestIp())
.setSalt(salt) .setSalt(salt)
.setType(type)
.setCreateDate(createDate) .setCreateDate(createDate)
.setExpireSecond(expireSecond) .setExpireSecond(expireSecond)
.setExpireDate(expireDate); .setExpireDate(expireDate);
......
...@@ -60,8 +60,13 @@ public class JwtRealmAppUser extends AuthorizingRealm { ...@@ -60,8 +60,13 @@ public class JwtRealmAppUser extends AuthorizingRealm {
@Override @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
log.debug("doGetAuthorizationInfo principalCollection..."); log.debug("doGetAuthorizationInfo principalCollection...");
/* // 设置角色/权限信息 // 设置角色/权限信息
JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal(); JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal();
if (!jwtToken.getType().equals("app")) {
return null;
}
/*
// 获取username // 获取username
String username = jwtToken.getUsername(); String username = jwtToken.getUsername();
// 获取登录用户角色权限信息 // 获取登录用户角色权限信息
......
...@@ -60,9 +60,16 @@ public class JwtRealmMerchant extends AuthorizingRealm { ...@@ -60,9 +60,16 @@ public class JwtRealmMerchant extends AuthorizingRealm {
*/ */
@Override @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
log.debug("doGetAuthorizationInfo principalCollection..."); log.debug("doGetAuthorizationInfo principalCollection...");
// 设置角色/权限信息 // 设置角色/权限信息
JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal(); JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal();
if (!jwtToken.getType().equals("mer")) {
return null;
}
// 获取username // 获取username
String username = jwtToken.getUsername(); String username = jwtToken.getUsername();
// 获取登录用户角色权限信息 // 获取登录用户角色权限信息
...@@ -73,6 +80,7 @@ public class JwtRealmMerchant extends AuthorizingRealm { ...@@ -73,6 +80,7 @@ public class JwtRealmMerchant extends AuthorizingRealm {
// 设置权限 // 设置权限
authorizationInfo.setStringPermissions(loginSysUserRedisVo.getPermissionCodes()); authorizationInfo.setStringPermissions(loginSysUserRedisVo.getPermissionCodes());
return authorizationInfo; return authorizationInfo;
} }
/** /**
......
...@@ -53,16 +53,19 @@ public class JwtRealmSystem extends AuthorizingRealm { ...@@ -53,16 +53,19 @@ public class JwtRealmSystem extends AuthorizingRealm {
} }
/** /**
* 授权认证,设置角色/权限信息 * 获取用户权限信息,包括角色以及权限。只有当触发检测用户权限时才会调用此方法,例如checkRole,checkPermission
* *
* @param principalCollection * @return AuthorizationInfo 权限信息
* @return
*/ */
@Override @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
log.debug("doGetAuthorizationInfo principalCollection..."); log.debug("doGetAuthorizationInfo principalCollection...");
// 设置角色/权限信息 // 设置角色/权限信息
JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal(); JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal();
if (!jwtToken.getType().equals("sys")){
return null;
}
// 获取username // 获取username
String username = jwtToken.getUsername(); String username = jwtToken.getUsername();
// 获取登录用户角色权限信息 // 获取登录用户角色权限信息
......
...@@ -103,7 +103,7 @@ public class ShiroLoginServiceImpl implements ShiroLoginService { ...@@ -103,7 +103,7 @@ public class ShiroLoginServiceImpl implements ShiroLoginService {
// 生成新token字符串 // 生成新token字符串
String newToken = JwtUtil.generateToken(username, salt, Duration.ofSeconds(expireSecond)); String newToken = JwtUtil.generateToken(username, salt, Duration.ofSeconds(expireSecond));
// 生成新JwtToken对象 // 生成新JwtToken对象
JwtToken newJwtToken = JwtToken.build(newToken, username, salt, expireSecond); JwtToken newJwtToken = JwtToken.build(newToken, username, salt, expireSecond,jwtToken.getType());
// 更新redis缓存 // 更新redis缓存
sysLoginRedisService.refreshLoginInfo(token, username, newJwtToken); sysLoginRedisService.refreshLoginInfo(token, username, newJwtToken);
log.debug("刷新token成功,原token:{},新token:{}", token, newToken); log.debug("刷新token成功,原token:{},新token:{}", token, newToken);
......
...@@ -32,6 +32,9 @@ import java.util.Date; ...@@ -32,6 +32,9 @@ import java.util.Date;
@Accessors(chain = true) @Accessors(chain = true)
public class JwtTokenRedisVo implements Serializable { public class JwtTokenRedisVo implements Serializable {
private static final long serialVersionUID = 1831633309466775223L; private static final long serialVersionUID = 1831633309466775223L;
private String type;
/** /**
* 登录ip * 登录ip
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment