门户网站登录
# SpringSecurity方式
在 ruoyi-common
模块中新建 PortalSysUser
文件
/**
* 门户网站用户对象
*/
@Data
public class PortalSysUser {
/**
* 用户ID
*/
@TableId
private Long userId;
/**
* 用户账号
*/
private String userName;
/**
* 手机号码
*/
private String phonenumber;
/**
* 密码
*/
private String password;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
复制 ruoyi-common
模块中 LoginUser
文件重命名为 PortalLoginUser
并修改代码
// SysUser 替换为 PortalSysUser
1
在 ruoyi-common
模块中新建 PortalSecurityUtils
文件
public class PortalSecurityUtils {
public static Long getUserId() {
try {
return getPortalLoginUser().getUserId();
} catch (Exception e) {
throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
}
}
public static String getUsername() {
try {
return getPortalLoginUser().getUsername();
} catch (Exception e) {
throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
}
}
public static PortalLoginUser getPortalLoginUser() {
try {
return (PortalLoginUser) getAuthentication().getPrincipal();
} catch (Exception e) {
throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
}
}
public static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
复制 ruoyi-framework
模块中 TokenService
文件重命名为 PortalTokenService
并修改代码
// LoginUser 替换为 PortalLoginUser
// LOGIN_USER_KEY 替换为 PORTAL_LOGIN_USER_KEY
// TOKEN_PREFIX 替换为 PORTAL_TOKEN_PREFIX
// LOGIN_TOKEN_KEY 替换为 PORTAL_LOGIN_TOKEN_KEY
// expireTime 替换为 portalExpireTime
1
2
3
4
5
2
3
4
5
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期(默认30分钟)
expireTime: 1440
# 门户网站令牌有效期
portalExpireTime: 0
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
/**
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
*
* @param loginUser
* @return 令牌
*/
public void verifyToken(PortalLoginUser loginUser) {
if (portalExpireTime > 0) {
long portalExpireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis();
if (portalExpireTime - currentTime <= MILLIS_MINUTE_TEN) {
refreshToken(loginUser);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 刷新令牌有效期
*
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser) {
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
String userKey = getTokenKey(loginUser.getToken());
if (expireTime > 0) {
redisCache.setCacheObject(userKey, loginUser, portalExpireTime, TimeUnit.MINUTES);
} else {
redisCache.setCacheObject(userKey, loginUser);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 修改认证过滤器
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private TokenService tokenService;
@Autowired
private PortalTokenService portalTokenService;
/**
* 使用 anonymous 或 permitAll 放行的资源也会经过此方法
* 使用 ignoring 放行的资源不会经过此方法
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) {
tokenService.verifyToken(loginUser);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
PortalLoginUser portalLoginUser = portalTokenService.getPortalLoginUser(request);
if (StringUtils.isNotNull(portalLoginUser) && StringUtils.isNull(PortalSecurityUtils.getAuthentication())) {
portalTokenService.verifyToken(portalLoginUser);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(portalLoginUser, null, portalLoginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
chain.doFilter(request, response);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 修改退出处理类
@Configuration
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
@Autowired
private TokenService tokenService;
@Autowired
private PortalTokenService portalTokenService;
/**
* 退出处理
*/
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser)) {
String userName = loginUser.getUsername();
// 删除用户缓存记录
tokenService.delLoginUser(loginUser.getToken());
// 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
}
PortalLoginUser portalLoginUser = portalTokenService.getPortalLoginUser(request);
if (StringUtils.isNotNull(portalLoginUser)) {
// 删除用户缓存记录
portalTokenService.delPortalLoginUser(portalLoginUser.getToken());
}
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "退出成功")));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 手机验证码登录
@Data
public class PortalLoginBody {
@NotEmpty(message = "手机号不能为空")
private String phone;
private String code;
}
1
2
3
4
5
6
2
3
4
5
6
@Slf4j
@RestController
@RequestMapping("/portal")
public class PortalSysLoginController {
@Autowired
private RedisCache redisCache;
@Autowired
private PortalSysUserService portalSysUserService;
@Autowired
private PortalTokenService portalTokenService;
@GetMapping("/getCode")
public AjaxResult getCode(@Validated PortalLoginBody portalLoginBody) {
// 缓存中数据格式:sms_codes:phone ==> code_startTime
String verifyKey = CacheConstants.SMS_CODE_KEY + portalLoginBody.getPhone();
String cacheCode = redisCache.getCacheObject(verifyKey);
// 限制1分钟内只能获取1次验证码
if (StringUtils.isNotEmpty(cacheCode)) {
long startTime = Long.parseLong(cacheCode.split("_")[1]);
if (System.currentTimeMillis() - startTime < 60 * 1000) {
return AjaxResult.error("访问过于频繁,请稍候再试");
}
}
// 发送验证码,10分钟内有效
String code = RandomUtil.randomNumbers(6);
redisCache.setCacheObject(verifyKey, code + "_" + System.currentTimeMillis(),
Constants.SMS_EXPIRATION, TimeUnit.MINUTES);
log.info("【若依】验证码:{},{}分钟内有效。如非本人操作,请忽略。", code, Constants.SMS_EXPIRATION);
return AjaxResult.success("验证码发送成功");
}
@PostMapping("/login")
public AjaxResult login(@Validated @RequestBody PortalLoginBody portalLoginBody) {
String verifyKey = CacheConstants.SMS_CODE_KEY + portalLoginBody.getPhone();
String cacheCode = redisCache.getCacheObject(verifyKey);
if (StringUtils.isNotEmpty(cacheCode)) {
if (cacheCode.split("_")[0].equals(portalLoginBody.getCode())) {
// 限制验证码只能使用1次
redisCache.deleteObject(verifyKey);
PortalSysUser portalSysUser = portalSysUserService.getOne(new LambdaQueryWrapper<PortalSysUser>()
.eq(PortalSysUser::getPhonenumber, portalLoginBody.getPhone()));
if (portalSysUser == null) {
portalSysUser = new PortalSysUser();
portalSysUser.setPhonenumber(portalLoginBody.getPhone());
portalSysUserService.save(portalSysUser);
}
PortalLoginUser portalLoginUser = new PortalLoginUser();
portalLoginUser.setUserId(portalSysUser.getUserId());
portalLoginUser.setUser(portalSysUser);
String token = portalTokenService.createToken(portalLoginUser);
return AjaxResult.success().put(Constants.TOKEN, token);
} else {
return AjaxResult.error(MessageUtils.message("user.jcaptcha.error"));
}
} else {
return AjaxResult.error(MessageUtils.message("user.jcaptcha.expire"));
}
}
@GetMapping("/getInfo")
public AjaxResult getInfo() {
PortalSysUser user = PortalSecurityUtils.getPortalLoginUser().getUser();
return AjaxResult.success().put("user", user);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/portal/getCode", "/portal/login");
}
1
2
3
4
5
2
3
4
5
# 测试功能
获取验证码(1分钟内只能获取1次验证码,10分钟内有效):http://127.0.0.1:8080/portal/getCode?phone=18132087340
登录(验证码只能使用1次):http://127.0.0.1:8080/portal/login
{
"phone": "18132087340",
"code": "666666"
}
1
2
3
4
2
3
4
获取用户信息:http://127.0.0.1:8080/portal/getInfo
参数名 | 参数值 |
---|---|
Authorization | Portal token |
退出登录(没登录也能调用):http://127.0.0.1:8080/logout
编辑 (opens new window)
上次更新: 2022-10-28 22:23:08