<artifactId>hutool-all</artifactId> | <artifactId>hutool-all</artifactId> | ||||
<version>4.6.10</version> | <version>4.6.10</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>io.projectreactor</groupId> | |||||
<artifactId>reactor-core</artifactId> | |||||
<version>3.2.5.RELEASE</version> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
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.RequiresPermissions; | |||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||
* 全国行政区域[sys_region]分页列表 | * 全国行政区域[sys_region]分页列表 | ||||
*/ | */ | ||||
@GetMapping("/getPageList") | @GetMapping("/getPageList") | ||||
@RequiresPermissions("/sysRegion/getPageList") | |||||
@ApiOperation(value = "获取SysRegion分页列表", notes = "全国行政区域[sys_region]分页列表", response = SysRegionQueryVo.class) | @ApiOperation(value = "获取SysRegion分页列表", notes = "全国行政区域[sys_region]分页列表", response = SysRegionQueryVo.class) | ||||
public ApiResult<PageTool<SysRegionQueryVo>> getSysRegionPageList(@Valid @RequestBody SysRegionQueryParam sysRegionQueryParam) throws Exception { | public ApiResult<PageTool<SysRegionQueryVo>> getSysRegionPageList(@Valid @RequestBody SysRegionQueryParam sysRegionQueryParam) throws Exception { | ||||
PageTool<SysRegionQueryVo> pageList = sysRegionService.getSysRegionPageList(sysRegionQueryParam); | PageTool<SysRegionQueryVo> pageList = sysRegionService.getSysRegionPageList(sysRegionQueryParam); | ||||
*/ | */ | ||||
@OperationLogger(value = "获取SysRegion列表") //这里添加了AOP的自定义注解 | @OperationLogger(value = "获取SysRegion列表") //这里添加了AOP的自定义注解 | ||||
@PostMapping("/getRegionList") | @PostMapping("/getRegionList") | ||||
@RequiresPermissions("/sysRegion/getRegionList") | |||||
@ApiOperation(value = "获取SysRegion列表", notes = "全国行政区域[sys_region]分页列表", response = SysRegionQueryVo.class) | @ApiOperation(value = "获取SysRegion列表", notes = "全国行政区域[sys_region]分页列表", response = SysRegionQueryVo.class) | ||||
public ApiResult<List<SysRegionQueryVo>> getSysRegionList(@Valid @RequestBody SysRegionQueryParam sysRegionQueryParam) throws Exception { | public ApiResult<List<SysRegionQueryVo>> getSysRegionList(@Valid @RequestBody SysRegionQueryParam sysRegionQueryParam) throws Exception { | ||||
return ApiResult.ok(sysRegionService.getSysRegionList(sysRegionQueryParam)); | return ApiResult.ok(sysRegionService.getSysRegionList(sysRegionQueryParam)); |
import com.xdf.creative.util.UUIDUtil; | import com.xdf.creative.util.UUIDUtil; | ||||
import com.xdf.creative.util.convert.SysUserConvert; | import com.xdf.creative.util.convert.SysUserConvert; | ||||
import com.xdf.creative.util.page.PageTool; | import com.xdf.creative.util.page.PageTool; | ||||
import io.swagger.annotations.Api; | |||||
import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
import cn.hutool.core.collection.CollectionUtil; | import cn.hutool.core.collection.CollectionUtil; | ||||
import org.apache.shiro.SecurityUtils; | import org.apache.shiro.SecurityUtils; | ||||
* @author DeanYe | * @author DeanYe | ||||
* @since 2019-10-24 | * @since 2019-10-24 | ||||
*/ | */ | ||||
@Api | |||||
@Slf4j | @Slf4j | ||||
@Service | @Service | ||||
public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser> implements SysUserService { | public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser> implements SysUserService { | ||||
String token = JwtUtil.generateToken(sysUser.getId(), userName, sysUser.getOrganizeId(),sysUser.getUserType(), newSalt, Duration.ofSeconds(expireSecond)); | String token = JwtUtil.generateToken(sysUser.getId(), userName, sysUser.getOrganizeId(),sysUser.getUserType(), newSalt, Duration.ofSeconds(expireSecond)); | ||||
log.debug("token:{}", token); | log.debug("token:{}", token); | ||||
// 创建AuthenticationToken | // 创建AuthenticationToken | ||||
JwtToken jwtToken = JwtToken.build(token, sysUser.getId(), userName, sysUser.getOrganizeId(),sysUser.getUserType(), newSalt, expireSecond); | |||||
JwtToken jwtToken = new JwtToken(token); | |||||
Subject subject = SecurityUtils.getSubject(); | Subject subject = SecurityUtils.getSubject(); | ||||
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken( | |||||
loginParam.getUsername(), | |||||
loginParam.getPassword()); | |||||
//进行验证,这里可以捕获异常,然后返回对应信息 | //进行验证,这里可以捕获异常,然后返回对应信息 | ||||
subject.login(usernamePasswordToken); | |||||
subject.login(jwtToken); | |||||
// 返回token和登陆用户信息对象 | // 返回token和登陆用户信息对象 | ||||
LoginSysUserTokenVo loginSysUserTokenVo = new LoginSysUserTokenVo(); | LoginSysUserTokenVo loginSysUserTokenVo = new LoginSysUserTokenVo(); | ||||
loginSysUserTokenVo.setToken("12wer234f345g34g45"); | |||||
loginSysUserTokenVo.setToken(token); | |||||
loginSysUserTokenVo.setLoginSysUserVo(loginSysUserVo); | loginSysUserTokenVo.setLoginSysUserVo(loginSysUserVo); | ||||
return loginSysUserTokenVo; | return loginSysUserTokenVo; | ||||
} | } |
package com.xdf.creative.shiro; | package com.xdf.creative.shiro; | ||||
import cn.hutool.core.collection.CollectionUtil; | import cn.hutool.core.collection.CollectionUtil; | ||||
import com.alibaba.fastjson.JSON; | |||||
import com.xdf.creative.base.vo.creative.SysRoleQueryVo; | import com.xdf.creative.base.vo.creative.SysRoleQueryVo; | ||||
import com.xdf.creative.enums.ApiCode; | |||||
import com.xdf.creative.module.entity.SysUser; | import com.xdf.creative.module.entity.SysUser; | ||||
import com.xdf.creative.module.service.SysPermissionService; | |||||
import com.xdf.creative.module.service.SysRoleService; | import com.xdf.creative.module.service.SysRoleService; | ||||
import com.xdf.creative.module.service.SysUserService; | import com.xdf.creative.module.service.SysUserService; | ||||
import com.xdf.creative.shiro.jwt.JwtToken; | |||||
import com.xdf.creative.shiro.jwt.JwtUtil; | |||||
import com.xdf.creative.support.exception.BusinessException; | import com.xdf.creative.support.exception.BusinessException; | ||||
import com.xdf.creative.util.StringUtil; | |||||
import com.xdf.creative.util.page.ApiResult; | |||||
import org.apache.shiro.authc.*; | import org.apache.shiro.authc.*; | ||||
import org.apache.shiro.authz.AuthorizationInfo; | import org.apache.shiro.authz.AuthorizationInfo; | ||||
import org.apache.shiro.authz.SimpleAuthorizationInfo; | import org.apache.shiro.authz.SimpleAuthorizationInfo; | ||||
import java.util.HashSet; | import java.util.HashSet; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Set; | |||||
public class CustomRealm extends AuthorizingRealm { | public class CustomRealm extends AuthorizingRealm { | ||||
private final static Logger log = LoggerFactory.getLogger(AuthorizingRealm.class); | private final static Logger log = LoggerFactory.getLogger(AuthorizingRealm.class); | ||||
private SysUserService sysUserService; | private SysUserService sysUserService; | ||||
@Autowired | @Autowired | ||||
private SysRoleService sysRoleService; | private SysRoleService sysRoleService; | ||||
@Autowired | |||||
private SysPermissionService sysPermissionService; | |||||
/** | |||||
* 必须重写此方法,不然Shiro会报错 | |||||
* | |||||
* @param token | |||||
* @return | |||||
*/ | |||||
@Override | |||||
public boolean supports(AuthenticationToken token) { | |||||
return token instanceof JwtToken; | |||||
} | |||||
@Override | @Override | ||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { | protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { | ||||
//获取登录用户名 | //获取登录用户名 | ||||
String name = (String) principalCollection.getPrimaryPrincipal(); | |||||
String token = (String) principalCollection.getPrimaryPrincipal(); | |||||
//根据用户名去数据库查询用户信息 | //根据用户名去数据库查询用户信息 | ||||
SysUser user = null; | SysUser user = null; | ||||
try { | try { | ||||
user = sysUserService.getSysUserByUserName(name); | |||||
if(null==user){ | |||||
user = sysUserService.getSysUserByUserName(JwtUtil.getUsername(token)); | |||||
if (null == user) { | |||||
return null; | return null; | ||||
} | } | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
HashSet<String> roleNameSet = new HashSet<>(); | HashSet<String> roleNameSet = new HashSet<>(); | ||||
HashSet<String> roleCodeSet = new HashSet<>(); | HashSet<String> roleCodeSet = new HashSet<>(); | ||||
List<SysRoleQueryVo> sysRoleQueryVoList = sysRoleService.getUserRoleByUserId(user.getId()); | |||||
List<SysRoleQueryVo> sysRoleQueryVoList = sysRoleService.getUserRoleByUserId(JwtUtil.getUserId(token)); | |||||
if (CollectionUtil.isEmpty(sysRoleQueryVoList)) { | if (CollectionUtil.isEmpty(sysRoleQueryVoList)) { | ||||
throw new BusinessException("角色不存在"); | throw new BusinessException("角色不存在"); | ||||
} | } | ||||
roleCodeSet.add(sysRoleQueryVo.getCode()); | roleCodeSet.add(sysRoleQueryVo.getCode()); | ||||
}); | }); | ||||
simpleAuthorizationInfo.setRoles(roleCodeSet); | simpleAuthorizationInfo.setRoles(roleCodeSet); | ||||
// simpleAuthorizationInfo.addStringPermission(permissions.getPermissionsName()); | |||||
Set<String> permissionSrt = null; | |||||
try { | |||||
permissionSrt = sysPermissionService.getPermissionUrlByUserId(JwtUtil.getUserId(token)); | |||||
} catch (Exception e) { | |||||
throw new BusinessException("资源不存在"); | |||||
} | |||||
simpleAuthorizationInfo.setStringPermissions(permissionSrt); | |||||
return simpleAuthorizationInfo; | return simpleAuthorizationInfo; | ||||
} | } | ||||
if (authenticationToken.getPrincipal() == null) { | if (authenticationToken.getPrincipal() == null) { | ||||
return null; | return null; | ||||
} | } | ||||
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken; | |||||
String token = (String) authenticationToken.getCredentials(); | |||||
//token失效 | |||||
if (JwtUtil.isExpired(token)) { | |||||
log.error("令牌过期"); | |||||
String result = JSON.toJSONString(ApiResult.fail(ApiCode.TOKEN_INVALID)); | |||||
throw new AuthenticationException(result); | |||||
} | |||||
String userName = JwtUtil.getUsername(token); | |||||
if (StringUtil.isEmpty(userName)) { | |||||
log.error("非法令牌"); | |||||
String result = JSON.toJSONString(ApiResult.fail(ApiCode.TOKEN_INVALID)); | |||||
throw new AuthenticationException(result); | |||||
} | |||||
//根据用户名去数据库查询用户信息 | //根据用户名去数据库查询用户信息 | ||||
SysUser user = null; | SysUser user = null; | ||||
//获取用户信息 | //获取用户信息 | ||||
String name =usernamePasswordToken.getUsername(); | |||||
try { | try { | ||||
user = sysUserService.getSysUserByUserName(name); | |||||
user = sysUserService.getSysUserByUserName(userName); | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
log.error("用户 { "+name+" } 不存在 "); | |||||
log.error("用户 { " + userName + " } 不存在 "); | |||||
throw new AccountException("账户不存在"); | throw new AccountException("账户不存在"); | ||||
} | } | ||||
if (user == null) { | if (user == null) { | ||||
throw new BusinessException("用户不存在"); | throw new BusinessException("用户不存在"); | ||||
} else { | } else { | ||||
//这里验证authenticationToken和simpleAuthenticationInfo的信息 | //这里验证authenticationToken和simpleAuthenticationInfo的信息 | ||||
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, usernamePasswordToken.getPassword().toString(), getName()); | |||||
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(token, token, getName()); | |||||
return simpleAuthenticationInfo; | return simpleAuthenticationInfo; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
* @author : lgw | * @author : lgw | ||||
* @date : 15:58 2020/3/3 | * @date : 15:58 2020/3/3 | ||||
*/ | */ | ||||
import com.xdf.creative.shiro.filter.JwtFilter; | |||||
import org.apache.shiro.SecurityUtils; | import org.apache.shiro.SecurityUtils; | ||||
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; | import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; | ||||
import org.apache.shiro.mgt.DefaultSubjectDAO; | import org.apache.shiro.mgt.DefaultSubjectDAO; | ||||
import org.apache.shiro.mgt.SecurityManager; | import org.apache.shiro.mgt.SecurityManager; | ||||
import org.apache.shiro.mgt.SubjectFactory; | |||||
import org.apache.shiro.spring.LifecycleBeanPostProcessor; | import org.apache.shiro.spring.LifecycleBeanPostProcessor; | ||||
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; | import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; | ||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean; | import org.apache.shiro.spring.web.ShiroFilterFactoryBean; | ||||
import org.apache.shiro.web.filter.authc.AnonymousFilter; | |||||
import org.apache.shiro.web.filter.authc.LogoutFilter; | |||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager; | import org.apache.shiro.web.mgt.DefaultWebSecurityManager; | ||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; | import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; | ||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||||
import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||
import org.springframework.context.annotation.DependsOn; | import org.springframework.context.annotation.DependsOn; | ||||
import javax.servlet.Filter; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.LinkedHashMap; | |||||
import java.util.Map; | import java.util.Map; | ||||
@Configuration | @Configuration | ||||
return customRealm; | return customRealm; | ||||
} | } | ||||
/* | |||||
* a. 告诉shiro不要使用默认的DefaultSubject创建对象,因为不能创建Session | |||||
* */ | |||||
@Bean | |||||
public SubjectFactory subjectFactory() { | |||||
return new StatelessWebSubjectFactory(); | |||||
} | |||||
//权限管理,配置主要是Realm的管理认证 | //权限管理,配置主要是Realm的管理认证 | ||||
@Bean | @Bean | ||||
public SecurityManager securityManager() { | public SecurityManager securityManager() { | ||||
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); | DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); | ||||
securityManager.setRealm(myShiroRealm()); | securityManager.setRealm(myShiroRealm()); | ||||
// 无状态subjectFactory设置 | // 无状态subjectFactory设置 | ||||
DefaultSessionStorageEvaluator evaluator = (DefaultSessionStorageEvaluator)((DefaultSubjectDAO) securityManager.getSubjectDAO()).getSessionStorageEvaluator(); | |||||
evaluator.setSessionStorageEnabled(Boolean.FALSE); | |||||
StatelessWebSubjectFactory subjectFactory = new StatelessWebSubjectFactory(); | |||||
securityManager.setSubjectFactory(subjectFactory); | |||||
SecurityUtils.setSecurityManager(securityManager); | |||||
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); | |||||
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); | |||||
defaultSessionStorageEvaluator.setSessionStorageEnabled(false); | |||||
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); | |||||
securityManager.setSubjectDAO(subjectDAO); | |||||
//禁止Subject的getSession方法 | |||||
securityManager.setSubjectFactory(subjectFactory()); | |||||
return securityManager; | return securityManager; | ||||
} | } | ||||
@Bean | @Bean | ||||
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { | public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { | ||||
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); | ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); | ||||
shiroFilterFactoryBean.setSecurityManager(securityManager); | |||||
Map<String, String> map = new HashMap<>(); | |||||
//登出 | |||||
map.put("/logout", "logout"); | |||||
//对所有用户认证 | |||||
map.put("/**", "authc"); | |||||
shiroFilterFactoryBean.setSecurityManager(securityManager()); | |||||
//登录 | //登录 | ||||
shiroFilterFactoryBean.setLoginUrl("/sysUser/login"); | shiroFilterFactoryBean.setLoginUrl("/sysUser/login"); | ||||
//首页 | //首页 | ||||
shiroFilterFactoryBean.setSuccessUrl("/index"); | shiroFilterFactoryBean.setSuccessUrl("/index"); | ||||
//错误页面,认证不通过跳转 | //错误页面,认证不通过跳转 | ||||
shiroFilterFactoryBean.setUnauthorizedUrl("/error"); | shiroFilterFactoryBean.setUnauthorizedUrl("/error"); | ||||
shiroFilterFactoryBean.setFilterChainDefinitionMap(map); | |||||
/* | |||||
* c. 添加jwt过滤器,并在下面注册 | |||||
* 也就是将jwtFilter注册到shiro的Filter中 | |||||
* 指定除了login和logout之外的请求都先经过jwtFilter | |||||
* */ | |||||
Map<String, Filter> filterMap = new HashMap<>(); | |||||
//这个地方其实另外两个filter可以不设置,默认就是 | |||||
filterMap.put("anon", new AnonymousFilter()); | |||||
filterMap.put("jwt", new JwtFilter()); | |||||
filterMap.put("logout", new LogoutFilter()); | |||||
shiroFilterFactoryBean.setFilters(filterMap); | |||||
// 拦截器 | |||||
Map<String, String> filterRuleMap = new LinkedHashMap<>(); | |||||
filterRuleMap.put("/sysUser/login", "anon"); | |||||
filterRuleMap.put("/logout", "logout"); | |||||
filterRuleMap.put("/**", "jwt"); | |||||
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterRuleMap); | |||||
return shiroFilterFactoryBean; | return shiroFilterFactoryBean; | ||||
} | } | ||||
/** | /** | ||||
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); | authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); | ||||
return authorizationAttributeSourceAdvisor; | return authorizationAttributeSourceAdvisor; | ||||
} | } | ||||
} | } |
return super.createSubject(context); | return super.createSubject(context); | ||||
} | } | ||||
public StatelessWebSubjectFactory() {} | |||||
} | } |
package com.xdf.creative.shiro.filter; | |||||
/** | |||||
* @author : lgw | |||||
* @date : 10:46 2020/3/4 | |||||
*/ | |||||
import com.alibaba.fastjson.JSON; | |||||
import com.xdf.creative.enums.ApiCode; | |||||
import com.xdf.creative.shiro.jwt.JwtProperties; | |||||
import com.xdf.creative.shiro.jwt.JwtToken; | |||||
import com.xdf.creative.util.page.ApiResult; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.shiro.authz.AuthorizationException; | |||||
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; | |||||
import org.apache.shiro.web.util.WebUtils; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.http.HttpStatus; | |||||
import org.springframework.stereotype.Component; | |||||
import org.springframework.web.bind.annotation.RequestMethod; | |||||
import javax.servlet.Filter; | |||||
import javax.servlet.ServletRequest; | |||||
import javax.servlet.ServletResponse; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
import javax.servlet.http.HttpServletResponse; | |||||
import java.io.IOException; | |||||
import java.io.PrintWriter; | |||||
import java.util.Date; | |||||
/** | |||||
* JwtFilter:jwt过滤器来作为shiro的过滤器 | |||||
* | |||||
* @author zhangxiaoxiang | |||||
* @date: 2019/07/12 | |||||
*/ | |||||
@Slf4j | |||||
@Component//这个注入与否影响不大 | |||||
public class JwtFilter extends BasicHttpAuthenticationFilter implements Filter { | |||||
@Autowired | |||||
private JwtProperties jwtProperties; | |||||
@Override | |||||
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) { | |||||
HttpServletRequest req = (HttpServletRequest) request; | |||||
String token = req.getHeader("Authorization"); | |||||
return token != null; | |||||
} | |||||
/** | |||||
* 返回结果为true表明登录通过 | |||||
*/ | |||||
@Override | |||||
protected boolean executeLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { | |||||
log.warn("onAccessDenied 方法被调用"); | |||||
//这个地方和前端约定,要求前端将jwtToken放在请求的Header部分 | |||||
//所以以后发起请求的时候就需要在Header中放一个Authorization,值就是对应的Token | |||||
HttpServletRequest request = (HttpServletRequest) servletRequest; | |||||
String token = request.getHeader("Authorization"); | |||||
if (null == token) { | |||||
return false; | |||||
} | |||||
log.info("请求的 Header 中藏有 jwtToken {}", token); | |||||
JwtToken jwtToken = new JwtToken(token); | |||||
try { | |||||
// 委托 realm 进行登录认证 | |||||
//所以这个地方最终还是调用JwtRealm进行的认证 | |||||
getSubject(servletRequest, servletResponse).login(jwtToken); | |||||
//也就是subject.login(token) | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
onLoginFail(servletResponse); | |||||
return false; | |||||
} | |||||
return true; | |||||
//执行方法中没有抛出异常就表示登录成功 | |||||
} | |||||
//登录失败时默认返回 401 状态码 | |||||
private void onLoginFail(ServletResponse response) throws IOException { | |||||
ApiResult result = new ApiResult(); | |||||
result.setCode(ApiCode.TOKEN_INVALID.getCode()); | |||||
result.setMsg(ApiCode.TOKEN_INVALID.getMsg()); | |||||
getResponseResult(response,result); | |||||
} | |||||
/** | |||||
* 这里我们详细说明下为什么重写 可以对比父类方法,只是将executeLogin方法调用去除了 | |||||
* 如果没有去除将会循环调用doGetAuthenticationInfo方法 | |||||
*/ | |||||
@Override | |||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { | |||||
this.sendChallenge(request, response); | |||||
return false; | |||||
} | |||||
/** | |||||
* 执行登录认证 | |||||
* | |||||
* @param request | |||||
* @param response | |||||
* @param mappedValue | |||||
* @return | |||||
*/ | |||||
@Override | |||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { | |||||
if (isLoginAttempt(request, response)) { | |||||
try { | |||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request; | |||||
executeLogin(request, response); | |||||
} catch (Exception e) { | |||||
log.error("JwtFilter过滤验证失败!"); | |||||
ApiResult result = new ApiResult(); | |||||
result.setCode(ApiCode.NOT_PERMISSION.getCode()); | |||||
result.setMsg("项目权限不足"); | |||||
getResponseResult(response,result); | |||||
//throw new AuthorizationException("项目权限不足", e); | |||||
} | |||||
return true; | |||||
}else { | |||||
ApiResult result = new ApiResult(); | |||||
result.setCode(ApiCode.TOKEN_INVALID.getCode()); | |||||
result.setMsg("无效Token请求"); | |||||
getResponseResult(response,result); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 返回结果 | |||||
* @param response | |||||
*/ | |||||
public void getResponseResult(ServletResponse response,ApiResult result){ | |||||
response.setCharacterEncoding("UTF-8"); | |||||
response.setContentType("application/json;charset=utf-8"); | |||||
PrintWriter printWriter = null; | |||||
try { | |||||
printWriter = WebUtils.toHttp(response).getWriter(); | |||||
printWriter.write(JSON.toJSONString(result)); | |||||
} catch (Exception e) { | |||||
log.error(e.getMessage(), e); | |||||
} finally { | |||||
if (null != printWriter) { | |||||
printWriter.close(); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* 对跨域提供支持 | |||||
* | |||||
* @param request | |||||
* @param response | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
@Override | |||||
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { | |||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request; | |||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response; | |||||
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin")); | |||||
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE"); | |||||
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers")); | |||||
// 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态 | |||||
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { | |||||
httpServletResponse.setStatus(HttpStatus.OK.value()); | |||||
return false; | |||||
} | |||||
return super.preHandle(request, response); | |||||
} | |||||
} |
import com.xdf.creative.util.IpUtil; | import com.xdf.creative.util.IpUtil; | ||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||
import org.apache.shiro.authc.AuthenticationToken; | |||||
import java.util.Date; | import java.util.Date; | ||||
**/ | **/ | ||||
@Data | @Data | ||||
@Accessors(chain = true) | @Accessors(chain = true) | ||||
public class JwtToken { | |||||
public class JwtToken implements AuthenticationToken { | |||||
private Long userId; | |||||
/** | |||||
* 登陆ip | |||||
*/ | |||||
private String host; | |||||
/** | |||||
* 登陆用户名称 | |||||
*/ | |||||
private String username; | |||||
/*** | |||||
* 组织id | |||||
*/ | |||||
private Long organizeId; | |||||
/*** | |||||
* 组织类型 0 普通用户 1、园区用户 2 区文创办 3市文创办 8后台管理 | |||||
*/ | |||||
private Integer organizeType; | |||||
/** | |||||
* 辖区id | |||||
*/ | |||||
private String regionId; | |||||
/** | |||||
* 登陆盐值 | |||||
*/ | |||||
private String salt; | |||||
/** | |||||
* 登陆token | |||||
*/ | |||||
private static final long serialVersionUID = 1L; | |||||
// 秘钥 | |||||
private String token; | private String token; | ||||
/** | |||||
* 创建时间 | |||||
*/ | |||||
private Date createDate; | |||||
/** | |||||
* 多长时间过期,默认一小时 | |||||
*/ | |||||
private long expireSecond; | |||||
/** | |||||
* 过期日期 | |||||
*/ | |||||
private Date expireDate; | |||||
private String principal; | |||||
private String credentials; | |||||
public JwtToken(String token) { | |||||
this.token = token; | |||||
} | |||||
@Override | |||||
public Object getPrincipal() { | |||||
return token; | |||||
} | |||||
public static JwtToken build(String token, Long userId, String username, Long organizeId, Integer organizeType, String salt, long expireSecond) { | |||||
DecodedJWT decodedJWT = JwtUtil.getJwtInfo(token); | |||||
Date createDate = decodedJWT.getIssuedAt(); | |||||
Date expireDate = decodedJWT.getExpiresAt(); | |||||
return new JwtToken() | |||||
.setUsername(username) | |||||
.setUserId(userId) | |||||
.setToken(token) | |||||
.setOrganizeType(organizeType) | |||||
.setOrganizeId(organizeId) | |||||
.setHost(IpUtil.getRequestIp()) | |||||
.setSalt(salt) | |||||
.setCreateDate(createDate) | |||||
.setExpireSecond(expireSecond) | |||||
.setExpireDate(expireDate); | |||||
@Override | |||||
public Object getCredentials() { | |||||
return token; | |||||
} | } | ||||
} | } |
############################ JWT start ############################# | ############################ JWT start ############################# | ||||
spring-boot-plus: | |||||
jwt: | jwt: | ||||
# token请求头名称 | # token请求头名称 | ||||
token-name: token | token-name: token |