| <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 |