forked from github/dataease
feat: 前后端auth模块重构
This commit is contained in:
parent
281caea95f
commit
b07ea4ab71
29
backend/src/main/java/io/dataease/auth/api/AuthApi.java
Normal file
29
backend/src/main/java/io/dataease/auth/api/AuthApi.java
Normal file
@ -0,0 +1,29 @@
|
||||
package io.dataease.auth.api;
|
||||
|
||||
import io.dataease.auth.api.dto.CurrentUserDto;
|
||||
import io.dataease.auth.api.dto.LoginDto;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
|
||||
@Api(tags = "权限:权限管理")
|
||||
@RequestMapping("/api/auth")
|
||||
public interface AuthApi {
|
||||
|
||||
|
||||
@PostMapping("/login")
|
||||
void login(LoginDto loginDto);
|
||||
|
||||
|
||||
@PostMapping("/userInfo")
|
||||
CurrentUserDto userInfo();
|
||||
|
||||
@GetMapping("/isLogin")
|
||||
Boolean isLogin();
|
||||
|
||||
|
||||
@GetMapping("/test")
|
||||
String test();
|
||||
}
|
13
backend/src/main/java/io/dataease/auth/api/dto/LoginDto.java
Normal file
13
backend/src/main/java/io/dataease/auth/api/dto/LoginDto.java
Normal file
@ -0,0 +1,13 @@
|
||||
package io.dataease.auth.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class LoginDto implements Serializable {
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
}
|
74
backend/src/main/java/io/dataease/auth/config/F2CRealm.java
Normal file
74
backend/src/main/java/io/dataease/auth/config/F2CRealm.java
Normal file
@ -0,0 +1,74 @@
|
||||
package io.dataease.auth.config;
|
||||
|
||||
import io.dataease.auth.entity.JWTToken;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.AuthenticationInfo;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
||||
import org.apache.shiro.authz.AuthorizationInfo;
|
||||
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||
import org.apache.shiro.realm.AuthorizingRealm;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
|
||||
@Component
|
||||
public class F2CRealm extends AuthorizingRealm {
|
||||
|
||||
@Resource
|
||||
private AuthUserService authUserService;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supports(AuthenticationToken token) {
|
||||
return token instanceof JWTToken;
|
||||
}
|
||||
|
||||
//验证资源权限
|
||||
@Override
|
||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||
String username = JWTUtils.getUsername(principals.toString());
|
||||
SysUserEntity user = authUserService.getUser(username);
|
||||
Long userId = user.getUserId();
|
||||
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
|
||||
Set<String> role = authUserService.roles(userId).stream().collect(Collectors.toSet());
|
||||
simpleAuthorizationInfo.addRoles(role);
|
||||
Set<String> permission = authUserService.permissions(userId).stream().collect(Collectors.toSet());
|
||||
simpleAuthorizationInfo.addStringPermissions(permission);
|
||||
return simpleAuthorizationInfo;
|
||||
}
|
||||
|
||||
//验证登录权限
|
||||
@Override
|
||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
|
||||
String token = (String) auth.getCredentials();
|
||||
// 解密获得username,用于和数据库进行对比
|
||||
String username = JWTUtils.getUsername(token);
|
||||
if (username == null) {
|
||||
throw new AuthenticationException("token invalid");
|
||||
}
|
||||
|
||||
SysUserEntity user = authUserService.getUser(username);
|
||||
if (user == null) {
|
||||
throw new AuthenticationException("User didn't existed!");
|
||||
}
|
||||
String pass = null;
|
||||
try {
|
||||
/*pass = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, userBean.getPassword());*/
|
||||
pass = user.getPassword();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (! JWTUtils.verify(token, username, pass)) {
|
||||
throw new AuthenticationException("Username or password error");
|
||||
}
|
||||
return new SimpleAuthenticationInfo(token, token, "f2cReam");
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package io.dataease.auth.config;
|
||||
|
||||
|
||||
import io.dataease.auth.service.ShiroService;
|
||||
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
|
||||
import org.apache.shiro.mgt.DefaultSubjectDAO;
|
||||
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import javax.servlet.Filter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import io.dataease.auth.filter.*;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
|
||||
@Configuration
|
||||
public class ShiroConfig {
|
||||
|
||||
|
||||
|
||||
@Bean("securityManager")
|
||||
public DefaultWebSecurityManager getManager(F2CRealm f2cRealm) {
|
||||
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
|
||||
// 使用自己的realm
|
||||
manager.setRealm(f2cRealm);
|
||||
|
||||
/*
|
||||
* 关闭shiro自带的session,详情见文档
|
||||
* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
|
||||
*/
|
||||
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
|
||||
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
|
||||
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
|
||||
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
|
||||
manager.setSubjectDAO(subjectDAO);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Bean("shiroFilter")
|
||||
public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager, ShiroService shiroService) {
|
||||
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
|
||||
// 添加自己的过滤器并且取名为jwt
|
||||
Map<String, Filter> filterMap = new LinkedHashMap<>();
|
||||
filterMap.put("f2cPerms", new F2CPermissionsFilter());
|
||||
//filterMap.put("f2cRoles", new F2CRolesFilter());
|
||||
filterMap.put("jwt", new JWTFilter());
|
||||
filterMap.put("logout", new F2CLogoutFilter());
|
||||
factoryBean.setFilters(filterMap);
|
||||
factoryBean.setSecurityManager(securityManager);
|
||||
factoryBean.setUnauthorizedUrl("/permissionMiss");
|
||||
factoryBean.setFilterChainDefinitionMap(shiroService.loadFilterChainDefinitionMap());
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下面的代码是添加注解支持
|
||||
*/
|
||||
@Bean
|
||||
@DependsOn("lifecycleBeanPostProcessor")
|
||||
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
|
||||
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
|
||||
return defaultAdvisorAutoProxyCreator;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
|
||||
return new LifecycleBeanPostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
|
||||
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
|
||||
advisor.setSecurityManager(securityManager);
|
||||
return advisor;
|
||||
}
|
||||
}
|
22
backend/src/main/java/io/dataease/auth/entity/JWTToken.java
Normal file
22
backend/src/main/java/io/dataease/auth/entity/JWTToken.java
Normal file
@ -0,0 +1,22 @@
|
||||
package io.dataease.auth.entity;
|
||||
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
|
||||
public class JWTToken implements AuthenticationToken {
|
||||
|
||||
private String token;
|
||||
|
||||
public JWTToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return token;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package io.dataease.auth.entity;
|
||||
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
|
||||
public class SysUserEntity implements Serializable {
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String username;
|
||||
|
||||
private String nickName;
|
||||
|
||||
private Long deptId;
|
||||
|
||||
private String password;
|
||||
|
||||
private Integer enabled;
|
||||
|
||||
private String email;
|
||||
|
||||
private String phone;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package io.dataease.auth.filter;
|
||||
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.filter.authc.LogoutFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
public class F2CLogoutFilter extends LogoutFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(F2CLogoutFilter.class);
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
|
||||
Subject subject = getSubject(request, response);
|
||||
try {
|
||||
subject.logout();
|
||||
} catch (Exception ex) {
|
||||
logger.error("退出登录错误",ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package io.dataease.auth.filter;
|
||||
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class F2CPermissionsFilter extends PermissionsAuthorizationFilter {
|
||||
|
||||
@Override
|
||||
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
|
||||
Subject subject = getSubject(request, response);
|
||||
String[] perms = (String[]) mappedValue;
|
||||
if (perms != null && perms.length > 0) {
|
||||
for (String str : perms) {
|
||||
// 判断访问的用户是否拥有mappedValue权限
|
||||
if (subject.isPermitted(str)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
121
backend/src/main/java/io/dataease/auth/filter/JWTFilter.java
Normal file
121
backend/src/main/java/io/dataease/auth/filter/JWTFilter.java
Normal file
@ -0,0 +1,121 @@
|
||||
package io.dataease.auth.filter;
|
||||
|
||||
import io.dataease.auth.entity.JWTToken;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
|
||||
|
||||
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
|
||||
/**
|
||||
* 判断用户是否想要登入。
|
||||
* 检测header里面是否包含Authorization字段即可
|
||||
*/
|
||||
@Override
|
||||
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
String authorization = req.getHeader("Authorization");
|
||||
return authorization != null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
String authorization = httpServletRequest.getHeader("Authorization");
|
||||
|
||||
if (JWTUtils.needRefresh(authorization)){
|
||||
authorization = refreshToken(request, response);
|
||||
}
|
||||
JWTToken token = new JWTToken(authorization);
|
||||
Subject subject = getSubject(request, response);
|
||||
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
|
||||
subject.login(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
@Override
|
||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||
if (isLoginAttempt(request, response)) {
|
||||
try {
|
||||
boolean loginSuccess = executeLogin(request, response);
|
||||
return loginSuccess;
|
||||
} catch (Exception e) {
|
||||
response401(request, response);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String refreshToken(ServletRequest request, ServletResponse response) {
|
||||
// 获取AccessToken(Shiro中getAuthzHeader方法已经实现)
|
||||
String token = this.getAuthzHeader(request);
|
||||
// 获取当前Token的帐号信息
|
||||
String username = JWTUtils.getUsername(token);
|
||||
String password = "123456";
|
||||
try {
|
||||
String newToken = JWTUtils.sign(username, password);
|
||||
JWTToken jwtToken = new JWTToken(newToken);
|
||||
this.getSubject(request, response).login(jwtToken);
|
||||
// 设置响应的Header头新Token
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
httpServletResponse.addHeader("Access-Control-Expose-Headers", "Authorization");
|
||||
httpServletResponse.setHeader("Authorization", newToken);
|
||||
return newToken;
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 对跨域提供支持
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将非法请求跳转到 /401
|
||||
*/
|
||||
private void response401(ServletRequest req, ServletResponse resp) {
|
||||
try {
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
|
||||
httpServletResponse.sendRedirect("/401");
|
||||
} catch (IOException e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package io.dataease.auth.server;
|
||||
|
||||
import io.dataease.auth.api.AuthApi;
|
||||
import io.dataease.auth.api.dto.CurrentRoleDto;
|
||||
import io.dataease.auth.api.dto.CurrentUserDto;
|
||||
import io.dataease.auth.api.dto.LoginDto;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.commons.utils.BeanUtils;
|
||||
import io.dataease.commons.utils.ServletUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
public class AuthServer implements AuthApi {
|
||||
|
||||
@Autowired
|
||||
private AuthUserService authUserService;
|
||||
|
||||
|
||||
@Override
|
||||
public void login(@RequestBody LoginDto loginDto) {
|
||||
String username = loginDto.getUsername();
|
||||
String password = loginDto.getPassword();
|
||||
SysUserEntity user = authUserService.getUser(username);
|
||||
String realPwd = user.getPassword();
|
||||
if (StringUtils.isEmpty(realPwd)){
|
||||
throw new RuntimeException("没有该用户!");
|
||||
}
|
||||
/*String pwd = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, password);
|
||||
String realPass = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, realPwd);
|
||||
if (!StrUtil.equals(pwd, realPass)){
|
||||
throw new RuntimeException("密码错误!");
|
||||
}*/
|
||||
if (!StringUtils.equals(realPwd, password)){
|
||||
throw new RuntimeException("密码错误!");
|
||||
}
|
||||
/*Map<String,Object> result = new HashMap<>();
|
||||
result.put("token", JWTUtils.sign(username, realPwd));*/
|
||||
String token = JWTUtils.sign(username, realPwd);
|
||||
ServletUtils.setToken(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CurrentUserDto userInfo() {
|
||||
String token = ServletUtils.getToken();
|
||||
String username = JWTUtils.getUsername(token);
|
||||
SysUserEntity user = authUserService.getUser(username);
|
||||
CurrentUserDto currentUserDto = BeanUtils.copyBean(new CurrentUserDto(), user);
|
||||
List<CurrentRoleDto> currentRoleDtos = authUserService.roleInfos(user.getUserId());
|
||||
currentUserDto.setRoles(currentRoleDtos);
|
||||
return currentUserDto;
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
public String logout(){
|
||||
return "success";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isLogin() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String test() {
|
||||
return "apple";
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package io.dataease.auth.service;
|
||||
|
||||
import io.dataease.auth.api.dto.CurrentRoleDto;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AuthUserService {
|
||||
|
||||
|
||||
|
||||
SysUserEntity getUser(String username);
|
||||
|
||||
List<String> roles(Long userId);
|
||||
|
||||
List<String> permissions(Long userId);
|
||||
|
||||
List<CurrentRoleDto> roleInfos(Long userId);
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package io.dataease.auth.service;
|
||||
|
||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ShiroService {
|
||||
|
||||
/**
|
||||
* 初始化权限 -> 拿全部权限
|
||||
*
|
||||
* @param :
|
||||
* @return: java.util.Map<java.lang.String,java.lang.String>
|
||||
*/
|
||||
Map<String, String> loadFilterChainDefinitionMap();
|
||||
|
||||
/**
|
||||
* 在对uri权限进行增删改操作时,需要调用此方法进行动态刷新加载数据库中的uri权限
|
||||
*
|
||||
* @param shiroFilterFactoryBean
|
||||
* @param roleId
|
||||
* @param isRemoveSession:
|
||||
* @return: void
|
||||
*/
|
||||
void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, Integer roleId, Boolean isRemoveSession);
|
||||
|
||||
/**
|
||||
* shiro动态权限加载 -> 原理:删除shiro缓存,重新执行doGetAuthorizationInfo方法授权角色和权限
|
||||
*
|
||||
* @param roleId
|
||||
* @param isRemoveSession:
|
||||
* @return: void
|
||||
*/
|
||||
void updatePermissionByRoleId(Integer roleId, Boolean isRemoveSession);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package io.dataease.auth.service.impl;
|
||||
|
||||
import io.dataease.auth.api.dto.CurrentRoleDto;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.base.mapper.ext.AuthMapper;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class AuthUserServiceImpl implements AuthUserService {
|
||||
|
||||
@Resource
|
||||
private AuthMapper authMapper;
|
||||
|
||||
|
||||
@Override
|
||||
public SysUserEntity getUser(String username){
|
||||
return authMapper.findUser(username);
|
||||
}
|
||||
@Override
|
||||
public List<String> roles(Long userId){
|
||||
return authMapper.roleCodes(userId);
|
||||
}
|
||||
@Override
|
||||
public List<String> permissions(Long userId){
|
||||
return authMapper.permissions(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CurrentRoleDto> roleInfos(Long userId) {
|
||||
return authMapper.roles(userId);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package io.dataease.auth.service.impl;
|
||||
|
||||
import io.dataease.auth.service.ShiroService;
|
||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@Service
|
||||
public class ShiroServiceImpl implements ShiroService {
|
||||
|
||||
@Override
|
||||
public Map<String, String> loadFilterChainDefinitionMap() {
|
||||
// 权限控制map
|
||||
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
|
||||
// 配置过滤:不会被拦截的链接 -> 放行 start ----------------------------------------------------------
|
||||
// 放行Swagger2页面,需要放行这些
|
||||
|
||||
filterChainDefinitionMap.put("/swagger-ui.html","anon");
|
||||
filterChainDefinitionMap.put("/swagger/**","anon");
|
||||
filterChainDefinitionMap.put("/webjars/**", "anon");
|
||||
filterChainDefinitionMap.put("/swagger-resources/**","anon");
|
||||
filterChainDefinitionMap.put("/v2/**","anon");
|
||||
filterChainDefinitionMap.put("/static/**", "anon");
|
||||
|
||||
// 登陆
|
||||
filterChainDefinitionMap.put("/api/auth/**", "anon");
|
||||
// 退出
|
||||
//filterChainDefinitionMap.put("/logout", "anon");
|
||||
// 放行未授权接口,重定向使用
|
||||
filterChainDefinitionMap.put("/unauth", "anon");
|
||||
filterChainDefinitionMap.put("/display/**", "anon");
|
||||
|
||||
// token过期接口
|
||||
filterChainDefinitionMap.put("/tokenExpired", "anon");
|
||||
// 被挤下线
|
||||
filterChainDefinitionMap.put("/downline", "anon");
|
||||
// 放行 end ----------------------------------------------------------
|
||||
filterChainDefinitionMap.put("/logout", "logout");
|
||||
|
||||
/*List<ExtPermissionBean> extPermissionBeans = extUserMapper.getPermissions();
|
||||
|
||||
extPermissionBeans.forEach(item -> {
|
||||
StringJoiner f2cPerms = new StringJoiner(",", "f2cPerms[", "]");
|
||||
f2cPerms.add(item.getPermission());
|
||||
filterChainDefinitionMap.put(item.getPath(), "jwt," + f2cPerms);
|
||||
});
|
||||
*/
|
||||
|
||||
filterChainDefinitionMap.put("/**", "jwt");
|
||||
return filterChainDefinitionMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, Integer roleId, Boolean isRemoveSession) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePermissionByRoleId(Integer roleId, Boolean isRemoveSession) {
|
||||
|
||||
}
|
||||
}
|
83
backend/src/main/java/io/dataease/auth/util/JWTUtils.java
Normal file
83
backend/src/main/java/io/dataease/auth/util/JWTUtils.java
Normal file
@ -0,0 +1,83 @@
|
||||
package io.dataease.auth.util;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.exceptions.JWTDecodeException;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class JWTUtils {
|
||||
|
||||
|
||||
// 过期时间5分钟
|
||||
private static final long EXPIRE_TIME = 5*60*1000;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 校验token是否正确
|
||||
* @param token 密钥
|
||||
* @param secret 用户的密码
|
||||
* @return 是否正确
|
||||
*/
|
||||
public static boolean verify(String token, String username, String secret) {
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
JWTVerifier verifier = JWT.require(algorithm)
|
||||
.withClaim("username", username)
|
||||
.build();
|
||||
verifier.verify(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得token中的信息无需secret解密也能获得
|
||||
* @return token中包含的用户名
|
||||
*/
|
||||
public static String getUsername(String token) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(token);
|
||||
return jwt.getClaim("username").asString();
|
||||
} catch (JWTDecodeException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static boolean needRefresh(String token){
|
||||
Date exp = JWTUtils.getExp(token);
|
||||
return new Date().getTime() >= exp.getTime();
|
||||
}
|
||||
|
||||
public static Date getExp(String token) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(token);
|
||||
return jwt.getClaim("exp").asDate();
|
||||
} catch (JWTDecodeException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名,5min后过期
|
||||
* @param username 用户名
|
||||
* @param secret 用户的密码
|
||||
* @return 加密的token
|
||||
*/
|
||||
public static String sign(String username, String secret) {
|
||||
try {
|
||||
Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
// 附带username信息
|
||||
return JWT.create()
|
||||
.withClaim("username", username)
|
||||
.withClaim("exp", date)
|
||||
.withExpiresAt(date)
|
||||
.sign(algorithm);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
23
frontend/src/utils/auth.js
Normal file
23
frontend/src/utils/auth.js
Normal file
@ -0,0 +1,23 @@
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
|
||||
const TokenKey = 'Authorization'
|
||||
const tokenCookieExpires = 1
|
||||
|
||||
export function getToken() {
|
||||
return Cookies.get(TokenKey)
|
||||
}
|
||||
|
||||
export function setToken(token, rememberMe) {
|
||||
if (rememberMe) {
|
||||
return Cookies.set(TokenKey, token, { expires: tokenCookieExpires })
|
||||
} else return Cookies.set(TokenKey, token)
|
||||
}
|
||||
|
||||
export function tokenKey(){
|
||||
return TokenKey
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return Cookies.remove(TokenKey)
|
||||
}
|
Loading…
Reference in New Issue
Block a user