commit
a86020b95c
@ -97,7 +97,9 @@ forest([ˈfôrəst],n.森林)是一款现代化的知识社区项目,使
|
|||||||
|
|
||||||
## 鸣谢
|
## 鸣谢
|
||||||
- 感谢 `JetBrains` 对本项目的帮助,为作者提供了开源许可版 `JetBrains` 全家桶
|
- 感谢 `JetBrains` 对本项目的帮助,为作者提供了开源许可版 `JetBrains` 全家桶
|
||||||
![JetBrains](src/main/resources/static/jetbrains.png)
|
|
||||||
|
![JetBrains](src/main/resources/static/jb_beam.svg)
|
||||||
|
|
||||||
|
|
||||||
## ⭐ Star 历史
|
## ⭐ Star 历史
|
||||||
|
|
||||||
|
14
pom.xml
14
pom.xml
@ -128,7 +128,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>fastjson</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
<version>2.0.15</version>
|
<version>2.0.16</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- shiro权限控制框架 -->
|
<!-- shiro权限控制框架 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -147,6 +147,12 @@
|
|||||||
<artifactId>commons-collections4</artifactId>
|
<artifactId>commons-collections4</artifactId>
|
||||||
<version>4.4</version>
|
<version>4.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.f4b6a3</groupId>
|
||||||
|
<artifactId>ulid-creator</artifactId>
|
||||||
|
<version>5.1.0</version>
|
||||||
|
</dependency>
|
||||||
<!--apache相关依赖-->
|
<!--apache相关依赖-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-lang</groupId>
|
<groupId>commons-lang</groupId>
|
||||||
@ -177,7 +183,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>druid-spring-boot-starter</artifactId>
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
<version>1.2.13-SNSAPSHOT</version>
|
<version>1.2.14</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
@ -255,12 +261,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-core</artifactId>
|
<artifactId>hutool-core</artifactId>
|
||||||
<version>5.8.8</version>
|
<version>5.8.9</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-http</artifactId>
|
<artifactId>hutool-http</artifactId>
|
||||||
<version>5.8.8</version>
|
<version>5.8.9</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.rymcu.forest.auth;
|
||||||
|
|
||||||
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
|
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
|
||||||
|
import org.apache.shiro.authz.UnauthenticatedException;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class BaseHashedCredentialsMatcher extends HashedCredentialsMatcher {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
|
||||||
|
TokenModel tokenModel = (TokenModel) token;
|
||||||
|
String accessToken = (String) tokenModel.getCredentials();
|
||||||
|
if (StringUtils.isBlank(accessToken)) {
|
||||||
|
throw new UnauthenticatedException();
|
||||||
|
}
|
||||||
|
TokenUser tokenUser = UserUtils.getTokenUser(accessToken);
|
||||||
|
if (Objects.isNull(tokenUser)) {
|
||||||
|
throw new UnauthenticatedException();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
package com.rymcu.forest.jwt.def;
|
package com.rymcu.forest.auth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
public class JwtConstants {
|
public class JwtConstants {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上线需要变更
|
* 上线需要变更
|
||||||
*/
|
*/
|
||||||
@ -15,7 +17,10 @@ public class JwtConstants {
|
|||||||
public static final String CURRENT_USER_NAME = "CURRENT_TOKEN_USER_NAME";
|
public static final String CURRENT_USER_NAME = "CURRENT_TOKEN_USER_NAME";
|
||||||
public static final String CURRENT_TOKEN_CLAIMS = "CURRENT_TOKEN_CLAIMS";
|
public static final String CURRENT_TOKEN_CLAIMS = "CURRENT_TOKEN_CLAIMS";
|
||||||
public static final String LAST_ONLINE = "last_online:";
|
public static final String LAST_ONLINE = "last_online:";
|
||||||
public static final long TOKEN_EXPIRES_HOUR = 2 * 60;
|
|
||||||
|
public static final long TOKEN_EXPIRES_HOUR = 2;
|
||||||
public static final long LAST_ONLINE_EXPIRES_MINUTE = 10;
|
public static final long LAST_ONLINE_EXPIRES_MINUTE = 10;
|
||||||
|
public static final long TOKEN_EXPIRES_MINUTE = 15;
|
||||||
|
public static final long REFRESH_TOKEN_EXPIRES_HOUR = 2;
|
||||||
|
|
||||||
}
|
}
|
118
src/main/java/com/rymcu/forest/auth/JwtFilter.java
Normal file
118
src/main/java/com/rymcu/forest/auth/JwtFilter.java
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package com.rymcu.forest.auth;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.UnauthenticatedException;
|
||||||
|
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||||
|
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;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2022/10/27 19:58.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
* @desc : com.rymcu.forest.auth
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class JwtFilter extends BasicHttpAuthenticationFilter {
|
||||||
|
/**
|
||||||
|
* 判断用户是否想要登入。
|
||||||
|
* 检测 header 里面是否包含 Authorization 字段即可
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
|
||||||
|
HttpServletRequest req = (HttpServletRequest) request;
|
||||||
|
String authorization = req.getHeader(JwtConstants.AUTHORIZATION);
|
||||||
|
return authorization != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean executeLogin(ServletRequest request, ServletResponse response) {
|
||||||
|
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||||
|
String authorization = httpServletRequest.getHeader(JwtConstants.AUTHORIZATION);
|
||||||
|
// 验证token
|
||||||
|
Claims claims;
|
||||||
|
try {
|
||||||
|
claims = Jwts.parser().setSigningKey(JwtConstants.JWT_SECRET).parseClaimsJws(authorization).getBody();
|
||||||
|
} catch (final SignatureException e) {
|
||||||
|
throw new UnauthenticatedException();
|
||||||
|
}
|
||||||
|
Object username = claims.getId();
|
||||||
|
if (Objects.isNull(username)) {
|
||||||
|
throw new UnauthenticatedException();
|
||||||
|
}
|
||||||
|
TokenModel token = new TokenModel(username.toString(), authorization);
|
||||||
|
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
|
||||||
|
getSubject(request, response).login(token);
|
||||||
|
// 如果没有抛出异常则代表登入成功,返回true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这里我们详细说明下为什么最终返回的都是true,即允许访问
|
||||||
|
* 例如我们提供一个地址 GET /article
|
||||||
|
* 登入用户和游客看到的内容是不同的
|
||||||
|
* 如果在这里返回了false,请求会被直接拦截,用户看不到任何东西
|
||||||
|
* 所以我们在这里返回true,Controller中可以通过 subject.isAuthenticated() 来判断用户是否登入
|
||||||
|
* 如果有些资源只有登入用户才能访问,我们只需要在方法上面加上 @RequiresAuthentication 注解即可
|
||||||
|
* 但是这样做有一个缺点,就是不能够对GET,POST等请求进行分别过滤鉴权(因为我们重写了官方的方法),但实际上对应用影响不大
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||||
|
if (isLoginAttempt(request, response)) {
|
||||||
|
try {
|
||||||
|
executeLogin(request, response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
response401(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对跨域提供支持
|
||||||
|
*/
|
||||||
|
@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 request, ServletResponse response) {
|
||||||
|
try {
|
||||||
|
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||||
|
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
httpResponse.setContentType("application/json;charset=utf-8");
|
||||||
|
httpResponse.getOutputStream().write("login fail".getBytes());
|
||||||
|
} catch (IOException e) {
|
||||||
|
// 错误日志
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
src/main/java/com/rymcu/forest/auth/JwtRealm.java
Normal file
75
src/main/java/com/rymcu/forest/auth/JwtRealm.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package com.rymcu.forest.auth;
|
||||||
|
|
||||||
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
|
import com.rymcu.forest.entity.Role;
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.service.RoleService;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
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 javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2022/10/27 20:04.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
* @desc : com.rymcu.forest.auth
|
||||||
|
*/
|
||||||
|
public class JwtRealm extends AuthorizingRealm {
|
||||||
|
@Resource
|
||||||
|
private RoleService roleService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TokenManager manager;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(AuthenticationToken token) {
|
||||||
|
return token instanceof TokenModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||||
|
String accessToken = (String) principals.getPrimaryPrincipal();
|
||||||
|
TokenUser tokenUser = UserUtils.getTokenUser(accessToken);
|
||||||
|
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
|
||||||
|
User user = new User();
|
||||||
|
user.setIdUser(tokenUser.getIdUser());
|
||||||
|
try {
|
||||||
|
List<Role> roles = roleService.selectRoleByUser(user);
|
||||||
|
for (Role role : roles) {
|
||||||
|
if (StringUtils.isNotBlank(role.getInputCode())) {
|
||||||
|
authorizationInfo.addRole(role.getInputCode());
|
||||||
|
authorizationInfo.addStringPermission(role.getInputCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 添加用户权限
|
||||||
|
authorizationInfo.addStringPermission("user");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return authorizationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证回调函数, 登录时调用,主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
|
||||||
|
TokenModel token = (TokenModel) authToken;
|
||||||
|
if (!manager.checkToken(token)) {
|
||||||
|
throw new AuthenticationException();
|
||||||
|
}
|
||||||
|
return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), this.getName());
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,7 @@
|
|||||||
package com.rymcu.forest.jwt.service;
|
package com.rymcu.forest.auth;
|
||||||
|
|
||||||
|
|
||||||
import com.rymcu.forest.handler.event.AccountEvent;
|
import com.rymcu.forest.handler.event.AccountEvent;
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.jwt.model.TokenModel;
|
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
@ -38,7 +36,7 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
//使用 account 作为源 token
|
//使用 account 作为源 token
|
||||||
String token = Jwts.builder().setId(id).setSubject(id).setIssuedAt(new Date()).signWith(SignatureAlgorithm.HS256, JwtConstants.JWT_SECRET).compact();
|
String token = Jwts.builder().setId(id).setSubject(id).setIssuedAt(new Date()).signWith(SignatureAlgorithm.HS256, JwtConstants.JWT_SECRET).compact();
|
||||||
//存储到 redis 并设置过期时间
|
//存储到 redis 并设置过期时间
|
||||||
redisTemplate.boundValueOps(id).set(token, JwtConstants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
|
redisTemplate.boundValueOps(id).set(token, JwtConstants.TOKEN_EXPIRES_MINUTE, TimeUnit.MINUTES);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +54,6 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
if (token == null || !token.equals(model.getToken())) {
|
if (token == null || !token.equals(model.getToken())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 如果验证成功,说明此用户进行了一次有效操作,延长 token 的过期时间
|
|
||||||
redisTemplate.boundValueOps(model.getUsername()).expire(JwtConstants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
|
|
||||||
StringBuilder key = new StringBuilder();
|
StringBuilder key = new StringBuilder();
|
||||||
key.append(JwtConstants.LAST_ONLINE).append(model.getUsername());
|
key.append(JwtConstants.LAST_ONLINE).append(model.getUsername());
|
||||||
String result = redisTemplate.boundValueOps(key.toString()).get();
|
String result = redisTemplate.boundValueOps(key.toString()).get();
|
@ -1,7 +1,4 @@
|
|||||||
package com.rymcu.forest.jwt.service;
|
package com.rymcu.forest.auth;
|
||||||
|
|
||||||
|
|
||||||
import com.rymcu.forest.jwt.model.TokenModel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对token进行操作的接口
|
* 对token进行操作的接口
|
||||||
@ -12,6 +9,7 @@ public interface TokenManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建一个token关联上指定用户
|
* 创建一个token关联上指定用户
|
||||||
|
* @param id
|
||||||
* @return 生成的token
|
* @return 生成的token
|
||||||
*/
|
*/
|
||||||
public String createToken(String id);
|
public String createToken(String id);
|
||||||
@ -25,6 +23,8 @@ public interface TokenManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 从字符串中解析token
|
* 从字符串中解析token
|
||||||
|
* @param token
|
||||||
|
* @param account
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public TokenModel getToken(String token, String account);
|
public TokenModel getToken(String token, String account);
|
@ -1,16 +1,22 @@
|
|||||||
package com.rymcu.forest.jwt.model;
|
package com.rymcu.forest.auth;
|
||||||
|
|
||||||
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token的Model类,可以增加字段提高安全性,例如时间戳、url签名
|
* Token的Model类,可以增加字段提高安全性,例如时间戳、url签名
|
||||||
* @author ScienJus
|
* @author ScienJus
|
||||||
* @date 2015/7/31.
|
* @date 2015/7/31.
|
||||||
*/
|
*/
|
||||||
public class TokenModel {
|
public class TokenModel implements AuthenticationToken {
|
||||||
|
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
|
public TokenModel(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
public TokenModel(String username, String token) {
|
public TokenModel(String username, String token) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
@ -31,4 +37,14 @@ public class TokenModel {
|
|||||||
public void setToken(String token) {
|
public void setToken(String token) {
|
||||||
this.token = token;
|
this.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCredentials() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,39 +0,0 @@
|
|||||||
package com.rymcu.forest.config;
|
|
||||||
|
|
||||||
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
|
|
||||||
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
|
|
||||||
import org.apache.shiro.web.util.WebUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ronger
|
|
||||||
*/
|
|
||||||
public class BaseSessionManager extends DefaultWebSessionManager {
|
|
||||||
private static final String AUTHORIZATION = "Authorization";
|
|
||||||
|
|
||||||
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
|
|
||||||
|
|
||||||
public BaseSessionManager() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
|
|
||||||
String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
|
|
||||||
// 如果请求头中有 Authorization 则其值为 sessionId
|
|
||||||
if (!StringUtils.isEmpty(id)) {
|
|
||||||
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
|
|
||||||
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
|
|
||||||
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
|
|
||||||
|
|
||||||
return id;
|
|
||||||
} else {
|
|
||||||
// 否则按默认规则从 cookie 取 sessionId
|
|
||||||
return super.getSessionId(request, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
package com.rymcu.forest.config;
|
|
||||||
|
|
||||||
import org.apache.shiro.mgt.SecurityManager;
|
|
||||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
|
||||||
import org.apache.shiro.web.filter.mgt.FilterChainManager;
|
|
||||||
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
|
|
||||||
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
|
|
||||||
import org.apache.shiro.web.mgt.WebSecurityManager;
|
|
||||||
import org.apache.shiro.web.servlet.AbstractShiroFilter;
|
|
||||||
import org.springframework.beans.factory.BeanInitializationException;
|
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ronger
|
|
||||||
* Shiro静态资源配置
|
|
||||||
* */
|
|
||||||
public class BaseShiroFilterFactoryBean extends ShiroFilterFactoryBean {
|
|
||||||
|
|
||||||
private Set<String> ignoreExt;
|
|
||||||
|
|
||||||
public BaseShiroFilterFactoryBean() {
|
|
||||||
super();
|
|
||||||
ignoreExt = new HashSet<>();
|
|
||||||
ignoreExt.add(".svg");
|
|
||||||
ignoreExt.add(".jpg");
|
|
||||||
ignoreExt.add(".png");
|
|
||||||
ignoreExt.add(".gif");
|
|
||||||
ignoreExt.add(".bmp");
|
|
||||||
ignoreExt.add(".js");
|
|
||||||
ignoreExt.add(".css");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AbstractShiroFilter createInstance() throws Exception {
|
|
||||||
|
|
||||||
SecurityManager securityManager = getSecurityManager();
|
|
||||||
if (securityManager == null) {
|
|
||||||
String msg = "SecurityManager property must be set.";
|
|
||||||
throw new BeanInitializationException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(securityManager instanceof WebSecurityManager)) {
|
|
||||||
String msg = "The security manager does not implement the WebSecurityManager interface.";
|
|
||||||
throw new BeanInitializationException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
FilterChainManager manager = createFilterChainManager();
|
|
||||||
|
|
||||||
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
|
|
||||||
chainResolver.setFilterChainManager(manager);
|
|
||||||
|
|
||||||
return new BaseSpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class BaseSpringShiroFilter extends AbstractShiroFilter {
|
|
||||||
|
|
||||||
protected BaseSpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
|
|
||||||
super();
|
|
||||||
if (webSecurityManager == null) {
|
|
||||||
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
|
|
||||||
}
|
|
||||||
setSecurityManager(webSecurityManager);
|
|
||||||
if (resolver != null) {
|
|
||||||
setFilterChainResolver(resolver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
|
|
||||||
FilterChain chain) throws ServletException, IOException {
|
|
||||||
HttpServletRequest request = (HttpServletRequest)servletRequest;
|
|
||||||
String str = request.getRequestURI().toLowerCase();
|
|
||||||
// 因为ShiroFilter 拦截所有请求(在上面我们配置了urlPattern 为 * ,当然你也可以在那里精确的添加要处理的路径,这样就不需要这个类了),而在每次请求里面都做了session的读取和更新访问时间等操作,这样在集群部署session共享的情况下,数量级的加大了处理量负载。
|
|
||||||
// 所以我们这里将一些能忽略的请求忽略掉。
|
|
||||||
// 当然如果你的集群系统使用了动静分离处理,静态资料的请求不会到Filter这个层面,便可以忽略。
|
|
||||||
boolean flag = true;
|
|
||||||
int idx = 0;
|
|
||||||
if(( idx = str.indexOf(".")) > 0){
|
|
||||||
str = str.substring(idx);
|
|
||||||
if(ignoreExt.contains(str.toLowerCase())) {
|
|
||||||
flag = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(flag){
|
|
||||||
super.doFilterInternal(servletRequest, servletResponse, chain);
|
|
||||||
}else{
|
|
||||||
chain.doFilter(servletRequest, servletResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,158 +0,0 @@
|
|||||||
package com.rymcu.forest.config;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import com.rymcu.forest.core.constant.ShiroConstants;
|
|
||||||
import com.rymcu.forest.core.exception.CaptchaException;
|
|
||||||
import com.rymcu.forest.entity.Permission;
|
|
||||||
import com.rymcu.forest.entity.Role;
|
|
||||||
import com.rymcu.forest.entity.User;
|
|
||||||
import com.rymcu.forest.service.PermissionService;
|
|
||||||
import com.rymcu.forest.service.RoleService;
|
|
||||||
import com.rymcu.forest.service.UserService;
|
|
||||||
import com.rymcu.forest.util.Encodes;
|
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.ibatis.exceptions.TooManyResultsException;
|
|
||||||
import org.apache.shiro.authc.*;
|
|
||||||
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.apache.shiro.util.ByteSource;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ronger
|
|
||||||
* @since 2018/05/28 11:00
|
|
||||||
* 自定义权限匹配和账号密码匹配
|
|
||||||
*/
|
|
||||||
public class BaseShiroRealm extends AuthorizingRealm {
|
|
||||||
@Resource
|
|
||||||
private RoleService roleService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private PermissionService permissionService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private UserService userService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
|
||||||
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
|
|
||||||
Principal principal = (Principal) principals.getPrimaryPrincipal();
|
|
||||||
User user = new User();
|
|
||||||
user.setIdUser(principal.getId());
|
|
||||||
try {
|
|
||||||
List<Role> roles = roleService.selectRoleByUser(user);
|
|
||||||
for (Role role : roles) {
|
|
||||||
if (StringUtils.isNotBlank(role.getInputCode())) {
|
|
||||||
authorizationInfo.addRole(role.getInputCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<Permission> permissions = permissionService.selectPermissionByUser(user);
|
|
||||||
for (Permission perm : permissions) {
|
|
||||||
if (perm.getPermissionCategory() != null) {
|
|
||||||
authorizationInfo.addStringPermission(perm.getPermissionCategory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 添加用户权限
|
|
||||||
authorizationInfo.addStringPermission("user");
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return authorizationInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证回调函数, 登录时调用,主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
|
|
||||||
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
|
|
||||||
//获取用户的输入的账号.
|
|
||||||
String username = token.getUsername();
|
|
||||||
|
|
||||||
User user = null;
|
|
||||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
|
||||||
if (!org.springframework.util.StringUtils.isEmpty(attributes.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) {
|
|
||||||
throw new CaptchaException();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
user = userService.findByAccount(username);
|
|
||||||
} catch (TooManyResultsException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
if (user == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// 账户冻结(是否允许登陆)
|
|
||||||
if (!"0".equals(user.getStatus())) {
|
|
||||||
throw new LockedAccountException();
|
|
||||||
}
|
|
||||||
byte[] salt = Encodes.decodeHex(user.getPassword().substring(0, 16));
|
|
||||||
return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()),
|
|
||||||
user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 授权用户信息
|
|
||||||
*/
|
|
||||||
public static class Principal implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
|
||||||
private Long id; // 编号
|
|
||||||
private String account; // 登录名
|
|
||||||
private String name; // 姓名
|
|
||||||
private boolean mobileLogin; // 是否手机登录
|
|
||||||
|
|
||||||
// private Map<String, Object> cacheMap;
|
|
||||||
|
|
||||||
public Principal(User user, boolean mobileLogin) {
|
|
||||||
this.id = user.getIdUser();
|
|
||||||
this.account = user.getAccount();
|
|
||||||
this.name = user.getNickname();
|
|
||||||
this.mobileLogin = mobileLogin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAccount() {
|
|
||||||
return account;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMobileLogin() {
|
|
||||||
return mobileLogin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取SESSIONID
|
|
||||||
*/
|
|
||||||
public String getSessionid() {
|
|
||||||
try {
|
|
||||||
return (String) Utils.getSession().getId();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return id.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package com.rymcu.forest.config;
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
import com.github.pagehelper.PageInterceptor;
|
import com.github.pagehelper.PageInterceptor;
|
||||||
import org.apache.ibatis.plugin.Interceptor;
|
|
||||||
import org.apache.ibatis.session.SqlSessionFactory;
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.rymcu.forest.config;
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.auth.JwtConstants;
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.service.UserService;
|
import com.rymcu.forest.service.UserService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -40,14 +39,13 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(Message message, byte[] pattern) {
|
public void onMessage(Message message, byte[] pattern) {
|
||||||
|
|
||||||
// 获取到失效的 key
|
// 获取到失效的 key
|
||||||
String expiredKey = message.toString();
|
String expiredKey = message.toString();
|
||||||
if (expiredKey.contains(JwtConstants.LAST_ONLINE)) {
|
if (expiredKey.contains(JwtConstants.LAST_ONLINE)) {
|
||||||
String email = expiredKey.replace(JwtConstants.LAST_ONLINE, "");
|
String account = expiredKey.replace(JwtConstants.LAST_ONLINE, "");
|
||||||
log.info("拿到过期的数据:{}", expiredKey);
|
log.info("拿到过期的数据:{}", expiredKey);
|
||||||
log.info("处理后的数据:{}", email);
|
log.info("处理后的数据:{}", account);
|
||||||
userService.updateLastOnlineTimeByEmail(email);
|
userService.updateLastOnlineTimeByAccount(account);
|
||||||
}
|
}
|
||||||
super.onMessage(message, pattern);
|
super.onMessage(message, pattern);
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
package com.rymcu.forest.config;
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
|
import com.rymcu.forest.auth.BaseHashedCredentialsMatcher;
|
||||||
|
import com.rymcu.forest.auth.JwtFilter;
|
||||||
|
import com.rymcu.forest.auth.JwtRealm;
|
||||||
import org.apache.shiro.mgt.SecurityManager;
|
import org.apache.shiro.mgt.SecurityManager;
|
||||||
import org.apache.shiro.session.mgt.SessionManager;
|
|
||||||
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
|
|
||||||
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.FormAuthenticationFilter;
|
|
||||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
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.core.env.Environment;
|
import org.springframework.context.annotation.DependsOn;
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
import javax.servlet.Filter;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -24,108 +21,46 @@ import java.util.Map;
|
|||||||
* @author ronger
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConfigurationProperties(prefix = "redis.shiro")
|
public class ShiroConfig {
|
||||||
public class ShiroConfig implements EnvironmentAware {
|
|
||||||
|
|
||||||
private Environment env;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(Environment environment) {
|
|
||||||
this.env=environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
|
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
|
||||||
ShiroFilterFactoryBean shiroFilterFactoryBean = new BaseShiroFilterFactoryBean();
|
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
|
||||||
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
||||||
|
//添加自定义的过滤器
|
||||||
|
LinkedHashMap<String, Filter> linkedHashMap = new LinkedHashMap<>();
|
||||||
|
linkedHashMap.put("jwt", new JwtFilter());
|
||||||
|
shiroFilterFactoryBean.setFilters(linkedHashMap);
|
||||||
|
|
||||||
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
|
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
|
||||||
//注意过滤器配置顺序 不能颠倒
|
filterChainDefinitionMap.put("/api/v1/console/**", "anon");
|
||||||
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl
|
filterChainDefinitionMap.put("/api/v1/open-data/**", "anon");
|
||||||
filterChainDefinitionMap.put("/logout", "logout");
|
filterChainDefinitionMap.put("/**", "jwt");
|
||||||
// 配置不会被拦截的链接 顺序判断
|
|
||||||
filterChainDefinitionMap.put("/druid/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/css/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/fonts/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/js/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/uploadFile/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/login", "anon");
|
|
||||||
|
|
||||||
filterChainDefinitionMap.put("/api/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/ws/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/wss/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/wx/**", "anon");
|
|
||||||
filterChainDefinitionMap.put("/**", "auth");
|
|
||||||
//配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
|
|
||||||
shiroFilterFactoryBean.setLoginUrl("/login");
|
|
||||||
// 登录成功后要跳转的链接
|
|
||||||
shiroFilterFactoryBean.setSuccessUrl("/index");
|
|
||||||
//未授权界面;
|
|
||||||
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
|
|
||||||
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
|
||||||
|
|
||||||
Map<String, Filter> filtersMap = new LinkedHashMap<>();
|
|
||||||
filtersMap.put("auth", baseFormAuthenticationFilter());
|
|
||||||
shiroFilterFactoryBean.setFilters(filtersMap);
|
|
||||||
|
|
||||||
filterChainDefinitionMap.put("/**", "auth");
|
|
||||||
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
||||||
|
|
||||||
return shiroFilterFactoryBean;
|
return shiroFilterFactoryBean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 凭证匹配器
|
|
||||||
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Bean
|
@Bean
|
||||||
public HashedCredentialsMatcher hashedCredentialsMatcher() {
|
public JwtRealm baseShiroRealm() {
|
||||||
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
|
JwtRealm shiroRealm = new JwtRealm();
|
||||||
// 散列算法:这里使用MD5算法;
|
shiroRealm.setCredentialsMatcher(new BaseHashedCredentialsMatcher());
|
||||||
hashedCredentialsMatcher.setHashAlgorithmName("SHA-1");
|
|
||||||
// 散列的次数,比如散列两次,相当于 md5(md5(""));
|
|
||||||
hashedCredentialsMatcher.setHashIterations(1024);
|
|
||||||
return hashedCredentialsMatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public BaseShiroRealm baseShiroRealm() {
|
|
||||||
BaseShiroRealm shiroRealm = new BaseShiroRealm();
|
|
||||||
shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
|
|
||||||
return shiroRealm;
|
return shiroRealm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
@Bean
|
* 配置安全管理器
|
||||||
public SecurityManager securityManager() {
|
|
||||||
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
|
||||||
securityManager.setRealm(baseShiroRealm());
|
|
||||||
// 自定义session管理 使用redis
|
|
||||||
securityManager.setSessionManager(sessionManager());
|
|
||||||
return securityManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义sessionManager
|
|
||||||
* */
|
* */
|
||||||
@Bean
|
@Bean
|
||||||
public SessionManager sessionManager() {
|
public SecurityManager securityManager() {
|
||||||
BaseSessionManager sessionManager = new BaseSessionManager();
|
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
|
||||||
sessionManager.setSessionDAO(new MemorySessionDAO());
|
defaultWebSecurityManager.setRealm(baseShiroRealm());
|
||||||
sessionManager.setSessionIdUrlRewritingEnabled(false);
|
return defaultWebSecurityManager;
|
||||||
sessionManager.setGlobalSessionTimeout(21600000L);
|
|
||||||
return sessionManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开启shiro aop注解支持.
|
* 开启shiro aop注解支持.
|
||||||
* 使用代理方式;所以需要开启代码支持;
|
* 使用代理方式;所以需要开启代码支持;
|
||||||
*
|
|
||||||
* @param securityManager
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
|
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
|
||||||
@ -136,37 +71,17 @@ public class ShiroConfig implements EnvironmentAware {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Shiro生命周期处理器
|
* Shiro生命周期处理器
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
|
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
|
||||||
return new LifecycleBeanPostProcessor();
|
return new LifecycleBeanPostProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
|
|
||||||
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Bean
|
@Bean
|
||||||
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
|
@DependsOn({"lifecycleBeanPostProcessor"})
|
||||||
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
|
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
|
||||||
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
|
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||||
return authorizationAttributeSourceAdvisor;
|
advisorAutoProxyCreator.setProxyTargetClass(true);
|
||||||
}
|
return advisorAutoProxyCreator;
|
||||||
|
|
||||||
public FormAuthenticationFilter baseFormAuthenticationFilter(){
|
|
||||||
FormAuthenticationFilter formAuthenticationFilter = new ShiroLoginFilter();
|
|
||||||
return formAuthenticationFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public FilterRegistrationBean someFilterRegistration() {
|
|
||||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
|
||||||
FormAuthenticationFilter baseFormAuthenticationFilter = new ShiroLoginFilter();
|
|
||||||
registration.setFilter(baseFormAuthenticationFilter);
|
|
||||||
registration.setEnabled(false);
|
|
||||||
return registration;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
package com.rymcu.forest.config;
|
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
|
||||||
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
|
||||||
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author wanwh
|
|
||||||
* @date 2019/1/24 0024
|
|
||||||
*/
|
|
||||||
public class ShiroLoginFilter extends FormAuthenticationFilter {
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在访问controller前判断是否登录,返回json,不进行重定向。
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
|
|
||||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
|
||||||
if (this.isLoginRequest(request, response)) {
|
|
||||||
if (this.isLoginSubmission(request, response)) {
|
|
||||||
if (log.isTraceEnabled()) {
|
|
||||||
log.trace("Login submission detected. Attempting to execute login.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.executeLogin(request, response);
|
|
||||||
} else {
|
|
||||||
if (log.isTraceEnabled()) {
|
|
||||||
log.trace("Login page view.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}else if(isAjax((HttpServletRequest) request)){
|
|
||||||
httpServletResponse.setContentType("application/json");
|
|
||||||
httpServletResponse.setCharacterEncoding("UTF-8");
|
|
||||||
httpServletResponse.setHeader("sessionstatus", "timeOut");
|
|
||||||
httpServletResponse.addHeader("loginPath", this.getLoginUrl());
|
|
||||||
httpServletResponse.getWriter().write(JSONObject.toJSONString(GlobalResultGenerator.genErrorResult("未登录或已登录超时,请重新登录"), SerializerFeature.PrettyFormat));
|
|
||||||
return false;
|
|
||||||
}else {
|
|
||||||
if (log.isTraceEnabled()) {
|
|
||||||
log.trace("Attempting to access a path which requires authentication. Forwarding to the Authentication url [" + this.getLoginUrl() + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.saveRequestAndRedirectToLogin(request, response);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAjax(HttpServletRequest request) {
|
|
||||||
String requestedWith = request.getHeader("x-requested-with");
|
|
||||||
if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
package com.rymcu.forest.config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户和密码(包含验证码)令牌类
|
|
||||||
* @author ronger
|
|
||||||
*/
|
|
||||||
public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private String captcha;
|
|
||||||
private boolean mobileLogin;
|
|
||||||
|
|
||||||
public UsernamePasswordToken() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UsernamePasswordToken(String username, char[] password,
|
|
||||||
boolean rememberMe, String host, String captcha, boolean mobileLogin) {
|
|
||||||
super(username, password, rememberMe, host);
|
|
||||||
this.captcha = captcha;
|
|
||||||
this.mobileLogin = mobileLogin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCaptcha() {
|
|
||||||
return captcha;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCaptcha(String captcha) {
|
|
||||||
this.captcha = captcha;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMobileLogin() {
|
|
||||||
return mobileLogin;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -4,17 +4,14 @@ package com.rymcu.forest.config;
|
|||||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||||
import com.rymcu.forest.jwt.aop.RestAuthTokenInterceptor;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||||
|
|
||||||
@ -60,22 +57,6 @@ public class WebMvcConfigurer extends WebMvcConfigurationSupport {
|
|||||||
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH");
|
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public RestAuthTokenInterceptor restAuthTokenInterceptor() {
|
|
||||||
return new RestAuthTokenInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加拦截器
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
registry.addInterceptor(restAuthTokenInterceptor()).addPathPatterns("/api/**")
|
|
||||||
.excludePathPatterns("/api/v1/console/**", "/api/v1/article/articles/**", "/api/v1/article/detail/**"
|
|
||||||
, "/api/v1/topic/**", "/api/v1/user/**", "/api/v1/article/*/comments", "/api/v1/rule/currency/**", "/api/v1/lucene/**", "/api/v1/open-data/**");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 访问静态资源
|
* 访问静态资源
|
||||||
*/
|
*/
|
||||||
|
@ -2,12 +2,10 @@ package com.rymcu.forest.core.service.log;
|
|||||||
|
|
||||||
import com.rymcu.forest.core.result.GlobalResult;
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
import com.rymcu.forest.core.service.log.annotation.TransactionLogger;
|
import com.rymcu.forest.core.service.log.annotation.TransactionLogger;
|
||||||
import com.rymcu.forest.entity.TransactionRecord;
|
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.enumerate.TransactionEnum;
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
import com.rymcu.forest.service.TransactionRecordService;
|
import com.rymcu.forest.service.TransactionRecordService;
|
||||||
import com.rymcu.forest.util.UserUtils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
import org.aspectj.lang.annotation.AfterReturning;
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
@ -15,11 +13,8 @@ import org.aspectj.lang.annotation.Pointcut;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package com.rymcu.forest.core.service.log;
|
package com.rymcu.forest.core.service.log;
|
||||||
|
|
||||||
|
import com.rymcu.forest.auth.JwtConstants;
|
||||||
import com.rymcu.forest.core.service.log.constant.LoggerConstant;
|
import com.rymcu.forest.core.service.log.constant.LoggerConstant;
|
||||||
import com.rymcu.forest.dto.TokenUser;
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
import com.rymcu.forest.entity.Visit;
|
import com.rymcu.forest.entity.Visit;
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.service.ArticleService;
|
import com.rymcu.forest.service.ArticleService;
|
||||||
import com.rymcu.forest.service.VisitService;
|
import com.rymcu.forest.service.VisitService;
|
||||||
import com.rymcu.forest.util.UserUtils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
@ -2,12 +2,12 @@ package com.rymcu.forest.core.service.security;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.rymcu.forest.auth.JwtConstants;
|
||||||
import com.rymcu.forest.core.service.security.annotation.AuthorshipInterceptor;
|
import com.rymcu.forest.core.service.security.annotation.AuthorshipInterceptor;
|
||||||
import com.rymcu.forest.dto.TokenUser;
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
import com.rymcu.forest.entity.Article;
|
import com.rymcu.forest.entity.Article;
|
||||||
import com.rymcu.forest.entity.Portfolio;
|
import com.rymcu.forest.entity.Portfolio;
|
||||||
import com.rymcu.forest.enumerate.Module;
|
import com.rymcu.forest.enumerate.Module;
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.mapper.UserMapper;
|
import com.rymcu.forest.mapper.UserMapper;
|
||||||
import com.rymcu.forest.service.ArticleService;
|
import com.rymcu.forest.service.ArticleService;
|
||||||
import com.rymcu.forest.service.PortfolioService;
|
import com.rymcu.forest.service.PortfolioService;
|
||||||
@ -76,7 +76,7 @@ public class AuthorshipAspect {
|
|||||||
}
|
}
|
||||||
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
||||||
String idArticle;
|
String idArticle;
|
||||||
Long idAuthor = 0l;
|
Long idAuthor = 0L;
|
||||||
if (isAjax(request)) {
|
if (isAjax(request)) {
|
||||||
Object[] objects = joinPoint.getArgs();
|
Object[] objects = joinPoint.getArgs();
|
||||||
JSONObject jsonObject;
|
JSONObject jsonObject;
|
||||||
|
@ -2,8 +2,8 @@ package com.rymcu.forest.core.service.security;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.rymcu.forest.auth.JwtConstants;
|
||||||
import com.rymcu.forest.dto.TokenUser;
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.util.UserUtils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
import com.rymcu.forest.web.api.exception.ErrorCode;
|
import com.rymcu.forest.web.api.exception.ErrorCode;
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package com.rymcu.forest.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ronger
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class SearchModel {
|
|
||||||
|
|
||||||
private String label;
|
|
||||||
|
|
||||||
private String value;
|
|
||||||
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
}
|
|
@ -3,6 +3,8 @@ package com.rymcu.forest.dto;
|
|||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
@ -18,10 +20,10 @@ public class TokenUser {
|
|||||||
|
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
private String avatarType;
|
|
||||||
|
|
||||||
private String avatarUrl;
|
private String avatarUrl;
|
||||||
|
|
||||||
private Integer weights;
|
private String refreshToken;
|
||||||
|
|
||||||
|
private Set<String> scope;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import com.alibaba.fastjson.annotation.JSONField;
|
|||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package com.rymcu.forest.dto.baidu;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ronger
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class TagNlpDTO {
|
|
||||||
|
|
||||||
private BigDecimal score;
|
|
||||||
|
|
||||||
private String tag;
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +1,14 @@
|
|||||||
package com.rymcu.forest.handler;
|
package com.rymcu.forest.handler;
|
||||||
|
|
||||||
import com.rymcu.forest.handler.event.AccountEvent;
|
import com.rymcu.forest.handler.event.AccountEvent;
|
||||||
|
import com.rymcu.forest.mapper.UserMapper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created on 2022/8/24 14:44.
|
* Created on 2022/8/24 14:44.
|
||||||
*
|
*
|
||||||
@ -17,10 +20,13 @@ import org.springframework.stereotype.Component;
|
|||||||
@Component
|
@Component
|
||||||
public class AccountHandler {
|
public class AccountHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
@EventListener
|
@EventListener
|
||||||
public void processAccountLastLoginEvent(AccountEvent accountEvent) {
|
public void processAccountLastOnlineTimeEvent(AccountEvent accountEvent) {
|
||||||
|
userMapper.updateLastOnlineTimeByAccount(accountEvent.getAccount());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
package com.rymcu.forest.jwt.aop;
|
|
||||||
|
|
||||||
|
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.jwt.model.TokenModel;
|
|
||||||
import com.rymcu.forest.jwt.service.TokenManager;
|
|
||||||
import com.rymcu.forest.mapper.UserMapper;
|
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
|
||||||
import com.rymcu.forest.web.api.exception.ErrorCode;
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import io.jsonwebtoken.Jwts;
|
|
||||||
import io.jsonwebtoken.SignatureException;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restful请求, Token校验规则拦截器(JWT)
|
|
||||||
*
|
|
||||||
* @author scott
|
|
||||||
* @date 2015/7/30.
|
|
||||||
*/
|
|
||||||
public class RestAuthTokenInterceptor implements HandlerInterceptor {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TokenManager manager;
|
|
||||||
@Resource
|
|
||||||
private UserMapper userMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse, Object obj, Exception exception) throws Exception {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
|
|
||||||
//从header中得到token
|
|
||||||
String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
|
|
||||||
if(StringUtils.isBlank(authHeader)){
|
|
||||||
authHeader = request.getHeader(JwtConstants.UPLOAD_TOKEN);
|
|
||||||
}
|
|
||||||
if (StringUtils.isBlank(authHeader)) {
|
|
||||||
throw new BaseApiException(ErrorCode.UNAUTHORIZED);
|
|
||||||
}
|
|
||||||
// 验证token
|
|
||||||
Claims claims = null;
|
|
||||||
try {
|
|
||||||
claims = Jwts.parser().setSigningKey(JwtConstants.JWT_SECRET).parseClaimsJws(authHeader).getBody();
|
|
||||||
}catch (final SignatureException e) {
|
|
||||||
throw new BaseApiException(ErrorCode.INVALID_TOKEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object username = claims.getId();
|
|
||||||
if (Objects.isNull(username)) {
|
|
||||||
throw new BaseApiException(ErrorCode.INVALID_TOKEN);
|
|
||||||
}
|
|
||||||
TokenModel model = manager.getToken(authHeader,username.toString());
|
|
||||||
if (manager.checkToken(model)) {
|
|
||||||
//如果token验证成功,将对象传递给下一个请求
|
|
||||||
request.setAttribute(JwtConstants.CURRENT_TOKEN_CLAIMS, claims);
|
|
||||||
//如果token验证成功,将token对应的用户id存在request中,便于之后注入
|
|
||||||
request.setAttribute(JwtConstants.CURRENT_USER_NAME, model.getUsername());
|
|
||||||
String uri = request.getRequestURI();
|
|
||||||
// 判断是否为后台接口或财政划转接口
|
|
||||||
String adminApi = "/admin/";
|
|
||||||
String transactionApi = "/transaction/";
|
|
||||||
if (uri.contains(adminApi) || uri.contains(transactionApi)) {
|
|
||||||
// 判断管理员权限
|
|
||||||
boolean hasPermission = userMapper.hasAdminPermission(model.getUsername());
|
|
||||||
if (hasPermission) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
throw new BaseApiException(ErrorCode.TOKEN_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postHandle(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse, Object obj, ModelAndView modelandview) throws Exception {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -17,8 +17,10 @@ import com.rymcu.forest.lucene.service.UserLuceneService;
|
|||||||
import com.rymcu.forest.lucene.util.ArticleIndexUtil;
|
import com.rymcu.forest.lucene.util.ArticleIndexUtil;
|
||||||
import com.rymcu.forest.lucene.util.PortfolioIndexUtil;
|
import com.rymcu.forest.lucene.util.PortfolioIndexUtil;
|
||||||
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
||||||
import com.rymcu.forest.util.Utils;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.rymcu.forest.lucene.lucene;
|
package com.rymcu.forest.lucene.lucene;
|
||||||
|
|
||||||
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
import com.rymcu.forest.lucene.model.UserLucene;
|
|
||||||
import org.apache.lucene.document.Document;
|
import org.apache.lucene.document.Document;
|
||||||
import org.apache.lucene.document.Field;
|
import org.apache.lucene.document.Field;
|
||||||
import org.apache.lucene.document.TextField;
|
import org.apache.lucene.document.TextField;
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package com.rymcu.forest.lucene.mapper;
|
package com.rymcu.forest.lucene.mapper;
|
||||||
|
|
||||||
import com.rymcu.forest.dto.PortfolioDTO;
|
import com.rymcu.forest.dto.PortfolioDTO;
|
||||||
import com.rymcu.forest.dto.UserDTO;
|
|
||||||
import com.rymcu.forest.entity.Portfolio;
|
|
||||||
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
import com.rymcu.forest.lucene.model.PortfolioLucene;
|
||||||
import com.rymcu.forest.lucene.model.UserLucene;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
@ -6,8 +6,6 @@ import lombok.Builder;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import javax.persistence.Id;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ArticleLucene
|
* ArticleLucene
|
||||||
*
|
*
|
||||||
|
@ -5,10 +5,6 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.apache.ibatis.type.JdbcType;
|
|
||||||
import tk.mybatis.mapper.annotation.ColumnType;
|
|
||||||
|
|
||||||
import javax.persistence.Column;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UserLucene
|
* UserLucene
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package com.rymcu.forest.lucene.service.impl;
|
package com.rymcu.forest.lucene.service.impl;
|
||||||
|
|
||||||
import com.rymcu.forest.dto.UserDTO;
|
import com.rymcu.forest.dto.UserDTO;
|
||||||
import com.rymcu.forest.lucene.lucene.UserBeanIndex;
|
|
||||||
import com.rymcu.forest.lucene.lucene.IKAnalyzer;
|
import com.rymcu.forest.lucene.lucene.IKAnalyzer;
|
||||||
|
import com.rymcu.forest.lucene.lucene.UserBeanIndex;
|
||||||
import com.rymcu.forest.lucene.mapper.UserLuceneMapper;
|
import com.rymcu.forest.lucene.mapper.UserLuceneMapper;
|
||||||
import com.rymcu.forest.lucene.model.UserLucene;
|
import com.rymcu.forest.lucene.model.UserLucene;
|
||||||
import com.rymcu.forest.lucene.service.UserLuceneService;
|
import com.rymcu.forest.lucene.service.UserLuceneService;
|
||||||
import com.rymcu.forest.lucene.util.LucenePath;
|
import com.rymcu.forest.lucene.util.LucenePath;
|
||||||
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
|
||||||
import com.rymcu.forest.lucene.util.SearchUtil;
|
import com.rymcu.forest.lucene.util.SearchUtil;
|
||||||
|
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
import org.apache.lucene.analysis.TokenStream;
|
import org.apache.lucene.analysis.TokenStream;
|
||||||
import org.apache.lucene.document.Document;
|
import org.apache.lucene.document.Document;
|
||||||
|
@ -20,7 +20,7 @@ public interface UserMapper extends Mapper<User> {
|
|||||||
* @param account
|
* @param account
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
User findByAccount(@Param("account") String account);
|
User selectByAccount(@Param("account") String account);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加用户权限
|
* 添加用户权限
|
||||||
@ -147,10 +147,10 @@ public interface UserMapper extends Mapper<User> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新用户最后在线时间
|
* 更新用户最后在线时间
|
||||||
* @param email
|
* @param account
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Integer updateLastOnlineTimeByEmail(@Param("email") String email);
|
Integer updateLastOnlineTimeByAccount(@Param("account") String account);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断用户是否拥有管理员权限
|
* 判断用户是否拥有管理员权限
|
||||||
|
@ -2,7 +2,6 @@ package com.rymcu.forest.service;
|
|||||||
|
|
||||||
import com.rymcu.forest.core.service.Service;
|
import com.rymcu.forest.core.service.Service;
|
||||||
import com.rymcu.forest.entity.ArticleThumbsUp;
|
import com.rymcu.forest.entity.ArticleThumbsUp;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -8,7 +8,7 @@ import com.rymcu.forest.entity.UserExtend;
|
|||||||
import org.apache.ibatis.exceptions.TooManyResultsException;
|
import org.apache.ibatis.exceptions.TooManyResultsException;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,7 +43,7 @@ public interface UserService extends Service<User> {
|
|||||||
* @param password 密码
|
* @param password 密码
|
||||||
* @return Map
|
* @return Map
|
||||||
*/
|
*/
|
||||||
TokenUser login(String account, String password) throws ServiceException;
|
TokenUser login(String account, String password);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过 account 获取用户信息接口
|
* 通过 account 获取用户信息接口
|
||||||
@ -169,10 +169,10 @@ public interface UserService extends Service<User> {
|
|||||||
/**
|
/**
|
||||||
* 通过邮箱更新用户最后登录时间
|
* 通过邮箱更新用户最后登录时间
|
||||||
*
|
*
|
||||||
* @param email
|
* @param account
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Integer updateLastOnlineTimeByEmail(String email);
|
Integer updateLastOnlineTimeByAccount(String account);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询用户扩展信息
|
* 查询用户扩展信息
|
||||||
@ -181,4 +181,18 @@ public interface UserService extends Service<User> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
UserExtend findUserExtendInfo(Long idUser);
|
UserExtend findUserExtendInfo(Long idUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新 token
|
||||||
|
* @param refreshToken
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
TokenUser refreshToken(String refreshToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户权限
|
||||||
|
* @param user
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Set<String> findUserPermissions(User user);
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,12 @@ import com.rymcu.forest.core.service.AbstractService;
|
|||||||
import com.rymcu.forest.dto.ArticleDTO;
|
import com.rymcu.forest.dto.ArticleDTO;
|
||||||
import com.rymcu.forest.entity.Sponsor;
|
import com.rymcu.forest.entity.Sponsor;
|
||||||
import com.rymcu.forest.entity.TransactionRecord;
|
import com.rymcu.forest.entity.TransactionRecord;
|
||||||
import com.rymcu.forest.entity.User;
|
|
||||||
import com.rymcu.forest.enumerate.TransactionCode;
|
import com.rymcu.forest.enumerate.TransactionCode;
|
||||||
import com.rymcu.forest.enumerate.TransactionEnum;
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
import com.rymcu.forest.mapper.SponsorMapper;
|
import com.rymcu.forest.mapper.SponsorMapper;
|
||||||
import com.rymcu.forest.service.ArticleService;
|
import com.rymcu.forest.service.ArticleService;
|
||||||
import com.rymcu.forest.service.SponsorService;
|
import com.rymcu.forest.service.SponsorService;
|
||||||
import com.rymcu.forest.service.TransactionRecordService;
|
import com.rymcu.forest.service.TransactionRecordService;
|
||||||
import com.rymcu.forest.util.UserUtils;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@ -126,9 +126,6 @@ public class TagServiceImpl extends AbstractService<Tag> implements TagService {
|
|||||||
throw new BusinessException("标签 '" + tag.getTagTitle() + "' 已存在!");
|
throw new BusinessException("标签 '" + tag.getTagTitle() + "' 已存在!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tag = new Tag();
|
|
||||||
tag.setTagTitle(tag.getTagTitle());
|
|
||||||
tag.setTagUri(tag.getTagUri());
|
|
||||||
if (StringUtils.isNotBlank(tag.getTagIconPath()) && tag.getTagIconPath().contains("base64")) {
|
if (StringUtils.isNotBlank(tag.getTagIconPath()) && tag.getTagIconPath().contains("base64")) {
|
||||||
String tagIconPath = UploadController.uploadBase64File(tag.getTagIconPath(), 2);
|
String tagIconPath = UploadController.uploadBase64File(tag.getTagIconPath(), 2);
|
||||||
tag.setTagIconPath(tagIconPath);
|
tag.setTagIconPath(tagIconPath);
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package com.rymcu.forest.service.impl;
|
package com.rymcu.forest.service.impl;
|
||||||
|
|
||||||
import com.github.pagehelper.PageHelper;
|
|
||||||
import com.github.pagehelper.PageInfo;
|
|
||||||
import com.rymcu.forest.core.exception.BusinessException;
|
import com.rymcu.forest.core.exception.BusinessException;
|
||||||
import com.rymcu.forest.core.exception.ServiceException;
|
import com.rymcu.forest.core.exception.ServiceException;
|
||||||
import com.rymcu.forest.core.service.AbstractService;
|
import com.rymcu.forest.core.service.AbstractService;
|
||||||
@ -60,9 +58,6 @@ public class TopicServiceImpl extends AbstractService<Topic> implements TopicSer
|
|||||||
throw new BusinessException("专题 '" + topic.getTopicTitle() + "' 已存在!");
|
throw new BusinessException("专题 '" + topic.getTopicTitle() + "' 已存在!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
topic = new Topic();
|
|
||||||
topic.setTopicTitle(topic.getTopicTitle());
|
|
||||||
topic.setTopicUri(topic.getTopicUri());
|
|
||||||
if (StringUtils.isNotBlank(topic.getTopicIconPath()) && topic.getTopicIconPath().contains("base64")) {
|
if (StringUtils.isNotBlank(topic.getTopicIconPath()) && topic.getTopicIconPath().contains("base64")) {
|
||||||
String topicIconPath = UploadController.uploadBase64File(topic.getTopicIconPath(), 3);
|
String topicIconPath = UploadController.uploadBase64File(topic.getTopicIconPath(), 3);
|
||||||
topic.setTopicIconPath(topicIconPath);
|
topic.setTopicIconPath(topicIconPath);
|
||||||
|
@ -13,7 +13,6 @@ import com.rymcu.forest.mapper.BankAccountMapper;
|
|||||||
import com.rymcu.forest.mapper.TransactionRecordMapper;
|
import com.rymcu.forest.mapper.TransactionRecordMapper;
|
||||||
import com.rymcu.forest.service.TransactionRecordService;
|
import com.rymcu.forest.service.TransactionRecordService;
|
||||||
import com.rymcu.forest.util.DateUtil;
|
import com.rymcu.forest.util.DateUtil;
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package com.rymcu.forest.service.impl;
|
package com.rymcu.forest.service.impl;
|
||||||
|
|
||||||
|
import com.github.f4b6a3.ulid.UlidCreator;
|
||||||
|
import com.rymcu.forest.auth.JwtConstants;
|
||||||
|
import com.rymcu.forest.auth.TokenManager;
|
||||||
import com.rymcu.forest.core.exception.*;
|
import com.rymcu.forest.core.exception.*;
|
||||||
import com.rymcu.forest.core.service.AbstractService;
|
import com.rymcu.forest.core.service.AbstractService;
|
||||||
import com.rymcu.forest.core.service.redis.RedisService;
|
|
||||||
import com.rymcu.forest.dto.*;
|
import com.rymcu.forest.dto.*;
|
||||||
import com.rymcu.forest.entity.Role;
|
import com.rymcu.forest.entity.Role;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.entity.UserExtend;
|
import com.rymcu.forest.entity.UserExtend;
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.jwt.service.TokenManager;
|
|
||||||
import com.rymcu.forest.lucene.model.UserLucene;
|
import com.rymcu.forest.lucene.model.UserLucene;
|
||||||
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
import com.rymcu.forest.lucene.util.UserIndexUtil;
|
||||||
import com.rymcu.forest.mapper.RoleMapper;
|
import com.rymcu.forest.mapper.RoleMapper;
|
||||||
@ -16,18 +16,20 @@ import com.rymcu.forest.mapper.UserExtendMapper;
|
|||||||
import com.rymcu.forest.mapper.UserMapper;
|
import com.rymcu.forest.mapper.UserMapper;
|
||||||
import com.rymcu.forest.service.LoginRecordService;
|
import com.rymcu.forest.service.LoginRecordService;
|
||||||
import com.rymcu.forest.service.UserService;
|
import com.rymcu.forest.service.UserService;
|
||||||
import com.rymcu.forest.util.BeanCopierUtil;
|
|
||||||
import com.rymcu.forest.util.Utils;
|
import com.rymcu.forest.util.Utils;
|
||||||
import com.rymcu.forest.web.api.common.UploadController;
|
import com.rymcu.forest.web.api.common.UploadController;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.ibatis.exceptions.TooManyResultsException;
|
import org.apache.ibatis.exceptions.TooManyResultsException;
|
||||||
import org.apache.shiro.authc.AuthenticationException;
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
import org.apache.shiro.authc.UnknownAccountException;
|
import org.apache.shiro.authc.UnknownAccountException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,8 +42,9 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
private UserMapper userMapper;
|
private UserMapper userMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private RoleMapper roleMapper;
|
private RoleMapper roleMapper;
|
||||||
@Resource
|
|
||||||
private RedisService redisService;
|
@Autowired
|
||||||
|
private StringRedisTemplate redisTemplate;
|
||||||
@Resource
|
@Resource
|
||||||
private TokenManager tokenManager;
|
private TokenManager tokenManager;
|
||||||
@Resource
|
@Resource
|
||||||
@ -54,16 +57,16 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User findByAccount(String account) throws TooManyResultsException {
|
public User findByAccount(String account) throws TooManyResultsException {
|
||||||
return userMapper.findByAccount(account);
|
return userMapper.selectByAccount(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean register(String email, String password, String code) {
|
public boolean register(String email, String password, String code) {
|
||||||
String vCode = redisService.get(email);
|
String vCode = redisTemplate.boundValueOps(email).get();
|
||||||
if (StringUtils.isNotBlank(vCode)) {
|
if (StringUtils.isNotBlank(vCode)) {
|
||||||
if (vCode.equals(code)) {
|
if (vCode.equals(code)) {
|
||||||
User user = userMapper.findByAccount(email);
|
User user = userMapper.selectByAccount(email);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
throw new AccountExistsException("该邮箱已被注册!");
|
throw new AccountExistsException("该邮箱已被注册!");
|
||||||
} else {
|
} else {
|
||||||
@ -77,7 +80,7 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
user.setUpdatedTime(user.getCreatedTime());
|
user.setUpdatedTime(user.getCreatedTime());
|
||||||
user.setAvatarUrl(DEFAULT_AVATAR);
|
user.setAvatarUrl(DEFAULT_AVATAR);
|
||||||
userMapper.insertSelective(user);
|
userMapper.insertSelective(user);
|
||||||
user = userMapper.findByAccount(email);
|
user = userMapper.selectByAccount(email);
|
||||||
Role role = roleMapper.selectRoleByInputCode("user");
|
Role role = roleMapper.selectRoleByInputCode("user");
|
||||||
userMapper.insertUserRole(user.getIdUser(), role.getIdRole());
|
userMapper.insertUserRole(user.getIdUser(), role.getIdRole());
|
||||||
UserIndexUtil.addIndex(UserLucene.builder()
|
UserIndexUtil.addIndex(UserLucene.builder()
|
||||||
@ -85,7 +88,7 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
.nickname(user.getNickname())
|
.nickname(user.getNickname())
|
||||||
.signature(user.getSignature())
|
.signature(user.getSignature())
|
||||||
.build());
|
.build());
|
||||||
redisService.delete(email);
|
redisTemplate.delete(email);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,17 +118,17 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TokenUser login(String account, String password) {
|
public TokenUser login(String account, String password) {
|
||||||
User user = userMapper.findByAccount(account);
|
User user = userMapper.selectByAccount(account);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
if (Utils.comparePwd(password, user.getPassword())) {
|
if (Utils.comparePwd(password, user.getPassword())) {
|
||||||
userMapper.updateLastLoginTime(user.getIdUser());
|
userMapper.updateLastLoginTime(user.getIdUser());
|
||||||
userMapper.updateLastOnlineTimeByEmail(user.getEmail());
|
userMapper.updateLastOnlineTimeByAccount(user.getAccount());
|
||||||
TokenUser tokenUser = new TokenUser();
|
TokenUser tokenUser = new TokenUser();
|
||||||
BeanCopierUtil.copy(user, tokenUser);
|
tokenUser.setToken(tokenManager.createToken(user.getAccount()));
|
||||||
tokenUser.setToken(tokenManager.createToken(user.getEmail()));
|
tokenUser.setRefreshToken(UlidCreator.getUlid().toString());
|
||||||
tokenUser.setWeights(userMapper.selectRoleWeightsByUser(user.getIdUser()));
|
redisTemplate.boundValueOps(tokenUser.getRefreshToken()).set(account, JwtConstants.REFRESH_TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
|
||||||
// 保存登录日志
|
// 保存登录日志
|
||||||
loginRecordService.saveLoginRecord(tokenUser.getIdUser());
|
loginRecordService.saveLoginRecord(user.getIdUser());
|
||||||
return tokenUser;
|
return tokenUser;
|
||||||
} else {
|
} else {
|
||||||
throw new AuthenticationException("密码错误");
|
throw new AuthenticationException("密码错误");
|
||||||
@ -142,7 +145,7 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean forgetPassword(String code, String password) throws ServiceException {
|
public boolean forgetPassword(String code, String password) throws ServiceException {
|
||||||
String email = redisService.get(code);
|
String email = redisTemplate.boundValueOps(code).get();
|
||||||
if (StringUtils.isBlank(email)) {
|
if (StringUtils.isBlank(email)) {
|
||||||
throw new ServiceException("链接已失效");
|
throw new ServiceException("链接已失效");
|
||||||
} else {
|
} else {
|
||||||
@ -250,7 +253,7 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
Long idUser = changeEmailDTO.getIdUser();
|
Long idUser = changeEmailDTO.getIdUser();
|
||||||
String email = changeEmailDTO.getEmail();
|
String email = changeEmailDTO.getEmail();
|
||||||
String code = changeEmailDTO.getCode();
|
String code = changeEmailDTO.getCode();
|
||||||
String vCode = redisService.get(email);
|
String vCode = redisTemplate.boundValueOps(email).get();
|
||||||
if (StringUtils.isNotBlank(vCode) && StringUtils.isNotBlank(code) && vCode.equals(code)) {
|
if (StringUtils.isNotBlank(vCode) && StringUtils.isNotBlank(code) && vCode.equals(code)) {
|
||||||
int result = userMapper.updateEmail(idUser, email);
|
int result = userMapper.updateEmail(idUser, email);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
@ -272,13 +275,13 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
public List<UserInfoDTO> findUsers(UserSearchDTO searchDTO) {
|
public List<UserInfoDTO> findUsers(UserSearchDTO searchDTO) {
|
||||||
List<UserInfoDTO> users = userMapper.selectUsers(searchDTO);
|
List<UserInfoDTO> users = userMapper.selectUsers(searchDTO);
|
||||||
users.forEach(user -> {
|
users.forEach(user -> {
|
||||||
user.setOnlineStatus(getUserOnlineStatus(user.getEmail()));
|
user.setOnlineStatus(getUserOnlineStatus(user.getAccount()));
|
||||||
});
|
});
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer getUserOnlineStatus(String email) {
|
private Integer getUserOnlineStatus(String account) {
|
||||||
String lastOnlineTime = redisService.get(JwtConstants.LAST_ONLINE + email);
|
String lastOnlineTime = redisTemplate.boundValueOps(JwtConstants.LAST_ONLINE + account).get();
|
||||||
if (StringUtils.isBlank(lastOnlineTime)) {
|
if (StringUtils.isBlank(lastOnlineTime)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -286,8 +289,8 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer updateLastOnlineTimeByEmail(String email) {
|
public Integer updateLastOnlineTimeByAccount(String account) {
|
||||||
return userMapper.updateLastOnlineTimeByEmail(email);
|
return userMapper.updateLastOnlineTimeByAccount(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -300,4 +303,36 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
}
|
}
|
||||||
return userExtend;
|
return userExtend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TokenUser refreshToken(String refreshToken) {
|
||||||
|
String account = redisTemplate.boundValueOps(refreshToken).get();
|
||||||
|
if (StringUtils.isNotBlank(account)) {
|
||||||
|
User nucleicUser = userMapper.selectByAccount(account);
|
||||||
|
if (nucleicUser != null) {
|
||||||
|
TokenUser tokenUser = new TokenUser();
|
||||||
|
tokenUser.setToken(tokenManager.createToken(nucleicUser.getAccount()));
|
||||||
|
tokenUser.setRefreshToken(UlidCreator.getUlid().toString());
|
||||||
|
redisTemplate.boundValueOps(tokenUser.getRefreshToken()).set(account, JwtConstants.REFRESH_TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
|
||||||
|
redisTemplate.delete(refreshToken);
|
||||||
|
return tokenUser;
|
||||||
|
} else {
|
||||||
|
throw new UnknownAccountException("未知账号");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> findUserPermissions(User user) {
|
||||||
|
Set<String> permissions = new HashSet<>();
|
||||||
|
List<Role> roles = roleMapper.selectRoleByIdUser(user.getIdUser());
|
||||||
|
for (Role role : roles) {
|
||||||
|
if (StringUtils.isNotBlank(role.getInputCode())) {
|
||||||
|
permissions.add(role.getInputCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
permissions.add("user");
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import com.rymcu.forest.util.BaiDuUtils;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
package com.rymcu.forest.util;
|
package com.rymcu.forest.util;
|
||||||
|
|
||||||
|
import com.rymcu.forest.auth.JwtConstants;
|
||||||
|
import com.rymcu.forest.auth.TokenManager;
|
||||||
|
import com.rymcu.forest.auth.TokenModel;
|
||||||
import com.rymcu.forest.dto.TokenUser;
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.jwt.model.TokenModel;
|
|
||||||
import com.rymcu.forest.jwt.service.TokenManager;
|
|
||||||
import com.rymcu.forest.mapper.UserMapper;
|
import com.rymcu.forest.mapper.UserMapper;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
|
||||||
import com.rymcu.forest.web.api.exception.ErrorCode;
|
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.SignatureException;
|
import io.jsonwebtoken.SignatureException;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.authz.UnauthorizedException;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ public class UserUtils {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static User getCurrentUserByToken() throws BaseApiException {
|
public static User getCurrentUserByToken() {
|
||||||
String authHeader = ContextHolderUtils.getRequest().getHeader(JwtConstants.AUTHORIZATION);
|
String authHeader = ContextHolderUtils.getRequest().getHeader(JwtConstants.AUTHORIZATION);
|
||||||
if (authHeader == null) {
|
if (authHeader == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -38,16 +37,16 @@ public class UserUtils {
|
|||||||
try {
|
try {
|
||||||
claims = Jwts.parser().setSigningKey(JwtConstants.JWT_SECRET).parseClaimsJws(authHeader).getBody();
|
claims = Jwts.parser().setSigningKey(JwtConstants.JWT_SECRET).parseClaimsJws(authHeader).getBody();
|
||||||
} catch (final SignatureException e) {
|
} catch (final SignatureException e) {
|
||||||
throw new BaseApiException(ErrorCode.UNAUTHORIZED);
|
throw new UnauthorizedException();
|
||||||
}
|
}
|
||||||
Object account = claims.getId();
|
Object account = claims.getId();
|
||||||
if (StringUtils.isNotBlank(Objects.toString(account, ""))) {
|
if (StringUtils.isNotBlank(Objects.toString(account, ""))) {
|
||||||
TokenModel model = tokenManager.getToken(authHeader, account.toString());
|
TokenModel model = tokenManager.getToken(authHeader, account.toString());
|
||||||
if (tokenManager.checkToken(model)) {
|
if (tokenManager.checkToken(model)) {
|
||||||
return userMapper.findByAccount(account.toString());
|
return userMapper.selectByAccount(account.toString());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new BaseApiException(ErrorCode.UNAUTHORIZED);
|
throw new UnauthorizedException();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -65,13 +64,12 @@ public class UserUtils {
|
|||||||
if (StringUtils.isNotBlank(Objects.toString(account, ""))) {
|
if (StringUtils.isNotBlank(Objects.toString(account, ""))) {
|
||||||
TokenModel model = tokenManager.getToken(token, account.toString());
|
TokenModel model = tokenManager.getToken(token, account.toString());
|
||||||
if (tokenManager.checkToken(model)) {
|
if (tokenManager.checkToken(model)) {
|
||||||
User user = userMapper.findByAccount(account.toString());
|
User user = userMapper.selectByAccount(account.toString());
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
TokenUser tokenUser = new TokenUser();
|
TokenUser tokenUser = new TokenUser();
|
||||||
BeanCopierUtil.copy(user, tokenUser);
|
BeanCopierUtil.copy(user, tokenUser);
|
||||||
tokenUser.setAccount(user.getEmail());
|
tokenUser.setAccount(user.getEmail());
|
||||||
tokenUser.setToken(token);
|
tokenUser.setToken(token);
|
||||||
tokenUser.setWeights(userMapper.selectRoleWeightsByUser(user.getIdUser()));
|
|
||||||
return tokenUser;
|
return tokenUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created on 2022/1/3 10:11.
|
* Created on 2022/1/3 10:11.
|
||||||
|
@ -7,7 +7,6 @@ import com.rymcu.forest.core.result.GlobalResultGenerator;
|
|||||||
import com.rymcu.forest.dto.TransactionRecordDTO;
|
import com.rymcu.forest.dto.TransactionRecordDTO;
|
||||||
import com.rymcu.forest.entity.CurrencyRule;
|
import com.rymcu.forest.entity.CurrencyRule;
|
||||||
import com.rymcu.forest.service.CurrencyRuleService;
|
import com.rymcu.forest.service.CurrencyRuleService;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
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.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
@ -15,9 +14,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created on 2022/3/6 18:26.
|
* Created on 2022/3/6 18:26.
|
||||||
|
@ -9,14 +9,12 @@ import com.rymcu.forest.dto.BankAccountDTO;
|
|||||||
import com.rymcu.forest.dto.UserInfoDTO;
|
import com.rymcu.forest.dto.UserInfoDTO;
|
||||||
import com.rymcu.forest.dto.admin.Dashboard;
|
import com.rymcu.forest.dto.admin.Dashboard;
|
||||||
import com.rymcu.forest.service.DashboardService;
|
import com.rymcu.forest.service.DashboardService;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
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.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
package com.rymcu.forest.web.api.auth;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.rymcu.forest.auth.TokenManager;
|
||||||
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
|
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
||||||
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.service.UserService;
|
||||||
|
import com.rymcu.forest.util.BeanCopierUtil;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/auth")
|
||||||
|
public class AuthController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserService userService;
|
||||||
|
@Resource
|
||||||
|
TokenManager tokenManager;
|
||||||
|
|
||||||
|
@PostMapping("/login")
|
||||||
|
public GlobalResult<TokenUser> login(@RequestBody User user) {
|
||||||
|
TokenUser tokenUser = userService.login(user.getAccount(), user.getPassword());
|
||||||
|
return GlobalResultGenerator.genSuccessResult(tokenUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/refresh-token")
|
||||||
|
public GlobalResult<TokenUser> refreshToken(@RequestBody TokenUser tokenUser) {
|
||||||
|
tokenUser = userService.refreshToken(tokenUser.getRefreshToken());
|
||||||
|
return GlobalResultGenerator.genSuccessResult(tokenUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/logout")
|
||||||
|
public GlobalResult logout() {
|
||||||
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
|
if (Objects.nonNull(user)) {
|
||||||
|
tokenManager.deleteToken(user.getAccount());
|
||||||
|
}
|
||||||
|
return GlobalResultGenerator.genSuccessResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/user")
|
||||||
|
public GlobalResult<JSONObject> user() {
|
||||||
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
|
TokenUser tokenUser = new TokenUser();
|
||||||
|
BeanCopierUtil.copy(user, tokenUser);
|
||||||
|
tokenUser.setScope(userService.findUserPermissions(user));
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
object.put("user", tokenUser);
|
||||||
|
return GlobalResultGenerator.genSuccessResult(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -8,14 +8,11 @@ import com.rymcu.forest.dto.BankAccountDTO;
|
|||||||
import com.rymcu.forest.dto.BankAccountSearchDTO;
|
import com.rymcu.forest.dto.BankAccountSearchDTO;
|
||||||
import com.rymcu.forest.dto.TransactionRecordDTO;
|
import com.rymcu.forest.dto.TransactionRecordDTO;
|
||||||
import com.rymcu.forest.service.BankAccountService;
|
import com.rymcu.forest.service.BankAccountService;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -4,20 +4,15 @@ import com.github.pagehelper.PageHelper;
|
|||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.rymcu.forest.core.result.GlobalResult;
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
||||||
import com.rymcu.forest.dto.ArticleDTO;
|
|
||||||
import com.rymcu.forest.dto.BankDTO;
|
import com.rymcu.forest.dto.BankDTO;
|
||||||
import com.rymcu.forest.entity.Bank;
|
|
||||||
import com.rymcu.forest.service.BankService;
|
import com.rymcu.forest.service.BankService;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
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.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -7,15 +7,15 @@ import com.rymcu.forest.core.result.GlobalResultGenerator;
|
|||||||
import com.rymcu.forest.core.service.security.annotation.SecurityInterceptor;
|
import com.rymcu.forest.core.service.security.annotation.SecurityInterceptor;
|
||||||
import com.rymcu.forest.dto.BankAccountDTO;
|
import com.rymcu.forest.dto.BankAccountDTO;
|
||||||
import com.rymcu.forest.dto.TransactionRecordDTO;
|
import com.rymcu.forest.dto.TransactionRecordDTO;
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.service.BankAccountService;
|
import com.rymcu.forest.service.BankAccountService;
|
||||||
import com.rymcu.forest.util.Utils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created on 2021/12/10 19:25.
|
* Created on 2021/12/10 19:25.
|
||||||
@ -31,20 +31,22 @@ public class WalletController {
|
|||||||
private BankAccountService bankAccountService;
|
private BankAccountService bankAccountService;
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/{idUser}")
|
@GetMapping("/detail")
|
||||||
@SecurityInterceptor
|
public GlobalResult<BankAccountDTO> detail() {
|
||||||
public GlobalResult<BankAccountDTO> detail(@PathVariable Long idUser) {
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
BankAccountDTO bankAccount = bankAccountService.findBankAccountByIdUser(idUser);
|
BankAccountDTO bankAccount = bankAccountService.findBankAccountByIdUser(user.getIdUser());
|
||||||
return GlobalResultGenerator.genSuccessResult(bankAccount);
|
return GlobalResultGenerator.genSuccessResult(bankAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/transaction-records")
|
@GetMapping("/transaction-records")
|
||||||
@SecurityInterceptor
|
|
||||||
public GlobalResult<PageInfo<TransactionRecordDTO>> transactionRecords(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "20") Integer rows, HttpServletRequest request) {
|
public GlobalResult<PageInfo<TransactionRecordDTO>> transactionRecords(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "20") Integer rows, HttpServletRequest request) {
|
||||||
String idUser = request.getParameter("idUser");
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
String startDate = request.getParameter("startDate");
|
String startDate = request.getParameter("startDate");
|
||||||
String endDate = request.getParameter("endDate");
|
String endDate = request.getParameter("endDate");
|
||||||
BankAccountDTO bankAccount = bankAccountService.findBankAccountByIdUser(Long.valueOf(idUser));
|
BankAccountDTO bankAccount = bankAccountService.findBankAccountByIdUser(user.getIdUser());
|
||||||
|
if (Objects.isNull(bankAccount)) {
|
||||||
|
return GlobalResultGenerator.genSuccessResult(new PageInfo<>());
|
||||||
|
}
|
||||||
PageHelper.startPage(page, rows);
|
PageHelper.startPage(page, rows);
|
||||||
List<TransactionRecordDTO> list = bankAccountService.findUserTransactionRecords(bankAccount.getBankAccount(), startDate, endDate);
|
List<TransactionRecordDTO> list = bankAccountService.findUserTransactionRecords(bankAccount.getBankAccount(), startDate, endDate);
|
||||||
PageInfo<TransactionRecordDTO> pageInfo = new PageInfo(list);
|
PageInfo<TransactionRecordDTO> pageInfo = new PageInfo(list);
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.rymcu.forest.web.api.common;
|
package com.rymcu.forest.web.api.common;
|
||||||
|
|
||||||
|
import com.rymcu.forest.auth.JwtConstants;
|
||||||
import com.rymcu.forest.core.result.GlobalResult;
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
||||||
import com.rymcu.forest.dto.LinkToImageUrlDTO;
|
import com.rymcu.forest.dto.LinkToImageUrlDTO;
|
||||||
import com.rymcu.forest.dto.TokenUser;
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
|
||||||
import com.rymcu.forest.service.ForestFileService;
|
import com.rymcu.forest.service.ForestFileService;
|
||||||
import com.rymcu.forest.util.FileUtils;
|
import com.rymcu.forest.util.FileUtils;
|
||||||
import com.rymcu.forest.util.SpringContextHolder;
|
import com.rymcu.forest.util.SpringContextHolder;
|
||||||
|
@ -9,14 +9,12 @@ import com.rymcu.forest.entity.Notification;
|
|||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.service.NotificationService;
|
import com.rymcu.forest.service.NotificationService;
|
||||||
import com.rymcu.forest.util.UserUtils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
import com.rymcu.forest.web.api.exception.ErrorCode;
|
import com.rymcu.forest.web.api.exception.ErrorCode;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,8 +17,6 @@ import com.rymcu.forest.web.api.exception.BaseApiException;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -8,12 +8,10 @@ import com.rymcu.forest.dto.ArticleDTO;
|
|||||||
import com.rymcu.forest.dto.LabelModel;
|
import com.rymcu.forest.dto.LabelModel;
|
||||||
import com.rymcu.forest.service.ArticleService;
|
import com.rymcu.forest.service.ArticleService;
|
||||||
import com.rymcu.forest.service.TagService;
|
import com.rymcu.forest.service.TagService;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -9,12 +9,10 @@ import com.rymcu.forest.dto.ArticleDTO;
|
|||||||
import com.rymcu.forest.entity.Topic;
|
import com.rymcu.forest.entity.Topic;
|
||||||
import com.rymcu.forest.service.ArticleService;
|
import com.rymcu.forest.service.ArticleService;
|
||||||
import com.rymcu.forest.service.TopicService;
|
import com.rymcu.forest.service.TopicService;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -13,13 +13,10 @@ import com.rymcu.forest.service.ArticleService;
|
|||||||
import com.rymcu.forest.service.FollowService;
|
import com.rymcu.forest.service.FollowService;
|
||||||
import com.rymcu.forest.service.PortfolioService;
|
import com.rymcu.forest.service.PortfolioService;
|
||||||
import com.rymcu.forest.service.UserService;
|
import com.rymcu.forest.service.UserService;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -13,13 +13,10 @@ import com.rymcu.forest.entity.LoginRecord;
|
|||||||
import com.rymcu.forest.entity.UserExtend;
|
import com.rymcu.forest.entity.UserExtend;
|
||||||
import com.rymcu.forest.service.LoginRecordService;
|
import com.rymcu.forest.service.LoginRecordService;
|
||||||
import com.rymcu.forest.service.UserService;
|
import com.rymcu.forest.service.UserService;
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
|
||||||
<mapper namespace="com.rymcu.forest.mapper.SearchMapper">
|
|
||||||
<resultMap id="BaseResultMap" type="com.rymcu.forest.dto.SearchModel">
|
|
||||||
<result column="label" property="label"></result>
|
|
||||||
<result column="value" property="value"></result>
|
|
||||||
<result column="type" property="type"></result>
|
|
||||||
</resultMap>
|
|
||||||
<select id="searchInitialArticleSearch" resultMap="BaseResultMap">
|
|
||||||
select article_title as label, id as value, 'article' as type from forest_article where article_status = 0
|
|
||||||
</select>
|
|
||||||
<select id="searchInitialPortfolioSearch" resultMap="BaseResultMap">
|
|
||||||
select portfolio_title as label, id as value, 'portfolio' as type from forest_portfolio
|
|
||||||
</select>
|
|
||||||
<select id="searchInitialUserSearch" resultMap="BaseResultMap">
|
|
||||||
select nickname as label, account as value, 'user' as type from forest_user where status = 0
|
|
||||||
</select>
|
|
||||||
</mapper>
|
|
@ -78,11 +78,11 @@
|
|||||||
<update id="updatePasswordById">
|
<update id="updatePasswordById">
|
||||||
update forest_user set password = #{password} where id = #{idUser}
|
update forest_user set password = #{password} where id = #{idUser}
|
||||||
</update>
|
</update>
|
||||||
<update id="updateLastOnlineTimeByEmail">
|
<update id="updateLastOnlineTimeByAccount">
|
||||||
update forest_user set last_online_time = sysdate() where email = #{email}
|
update forest_user set last_online_time = sysdate() where account = #{account}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<select id="findByAccount" resultMap="BaseResultMap">
|
<select id="selectByAccount" resultMap="BaseResultMap">
|
||||||
select id, nickname, account, password, status, avatar_type, avatar_url, email from forest_user where (account = #{account} or email = #{account} ) and status = 0
|
select id, nickname, account, password, status, avatar_type, avatar_url, email from forest_user where (account = #{account} or email = #{account} ) and status = 0
|
||||||
</select>
|
</select>
|
||||||
<select id="findUserInfoByAccount" resultMap="UserInfoResultMapper">
|
<select id="findUserInfoByAccount" resultMap="UserInfoResultMapper">
|
||||||
|
100
src/main/resources/application-dev.yml
Normal file
100
src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANbY1W9TXU+OdseRBVw5/eq1rs5UVQZie5ydEPYIurRzF4oBORu/+Sjqt+c5mHulleuiD4Yov+0e/CXODg4FYu8CAwEAAQ==
|
||||||
|
spring:
|
||||||
|
thymeleaf:
|
||||||
|
prefix: classpath:/templates/
|
||||||
|
suffix: .html
|
||||||
|
mode: HTML
|
||||||
|
encoding: UTF-8
|
||||||
|
servlet:
|
||||||
|
content-type: text/html
|
||||||
|
cache: false
|
||||||
|
redis:
|
||||||
|
host: 192.168.31.200
|
||||||
|
port: 6379
|
||||||
|
password: d9d2j9w2
|
||||||
|
database: 1
|
||||||
|
timeout: 3000
|
||||||
|
jedis:
|
||||||
|
pool:
|
||||||
|
max-active: 8
|
||||||
|
max-wait: 1
|
||||||
|
max-idle: 500
|
||||||
|
min-idle: 0
|
||||||
|
datasource:
|
||||||
|
druid:
|
||||||
|
url: jdbc:mysql://192.168.31.200:3306/forest?characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
|
||||||
|
username: root
|
||||||
|
password: Ldh1NrsXJntz5nTXeO0nPh+8s1FMe+JHCfXy2Zj3egqqjegN+mNe+53ZmduUlVdE4ZqKuUho7T9yftc6AYYKog==
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||||
|
time-between-eviction-runs-millis: 60000
|
||||||
|
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||||
|
min-evictable-idle-time-millis: 30000
|
||||||
|
validation-query: SELECT 1 FROM DUAL
|
||||||
|
test-while-idle: true
|
||||||
|
test-on-borrow: false
|
||||||
|
test-on-return: false
|
||||||
|
connection-properties: config.decrypt=true;config.decrypt.key=${publickey}
|
||||||
|
filters: config,stat
|
||||||
|
max-pool-prepared-statement-per-connection-size: 100
|
||||||
|
stat-view-servlet:
|
||||||
|
enabled: true
|
||||||
|
allow:
|
||||||
|
login-username: admin
|
||||||
|
login-password: rymcu.Test1
|
||||||
|
filter:
|
||||||
|
stat:
|
||||||
|
log-slow-sql: true
|
||||||
|
mail:
|
||||||
|
host: smtp.ym.163.com
|
||||||
|
port: 465
|
||||||
|
username: service@rymcu.com
|
||||||
|
password: 4W3tCXdyk0Gm
|
||||||
|
wx:
|
||||||
|
open:
|
||||||
|
componentAppId: wx9c4a7dfb3238d5f6
|
||||||
|
componentSecret: e32a6f75ab6b746ec3ae38a39a79ba22
|
||||||
|
componentToken: rymcu
|
||||||
|
componentAesKey: NWIwMDQyZjU0YWI2NGFlZThkOWZhZTg3NTg4NzQwN2E
|
||||||
|
mp:
|
||||||
|
configs:
|
||||||
|
- appId: wxf085386aa07c0857
|
||||||
|
secret: aabd075d2851764714fd14a0d0b1b8b4
|
||||||
|
token: rymcu
|
||||||
|
aesKey: lvn3mMSnFOvbnIJVNhHQqjWb9swe66L1xIcerJSs0fm
|
||||||
|
- appId: wxa49093339a5a822b
|
||||||
|
secret: 29e9390e6d58d57a2b2a2350dbee8754
|
||||||
|
token: qwert
|
||||||
|
aesKey:
|
||||||
|
miniapp:
|
||||||
|
configs:
|
||||||
|
- appid: wxb4fff78a6b878cf7
|
||||||
|
secret: c8735d0ccc8497b8509dc2762246cb37
|
||||||
|
token: #微信小程序消息服务器配置的token
|
||||||
|
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
||||||
|
msgDataFormat: JSON
|
||||||
|
env: dev
|
||||||
|
logging:
|
||||||
|
file:
|
||||||
|
path: /logs/forest
|
||||||
|
level:
|
||||||
|
com:
|
||||||
|
rymcu: info
|
||||||
|
server:
|
||||||
|
port: 8099
|
||||||
|
servlet:
|
||||||
|
context-path: /forest
|
||||||
|
max-http-header-size: 1048576
|
||||||
|
version: 1.0
|
||||||
|
resource:
|
||||||
|
domain: http://test.rymcu.com
|
||||||
|
file-path: http://test.rymcu.com
|
||||||
|
pic-path: /opt/nebula/static
|
||||||
|
baidu:
|
||||||
|
data:
|
||||||
|
site: https://rymcu.com
|
||||||
|
token: 9cdKR6bVCJzxDEJS
|
||||||
|
ai:
|
||||||
|
appId: 22891829
|
||||||
|
appKey: HKxdO8ioaUmltZh0eaOVMsmW
|
||||||
|
secretKey: GXOtl3XtiIkVA3CPsc3c29Pqa4V290Yr
|
Loading…
Reference in New Issue
Block a user