目录

门户网站登录

# 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

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

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








 
 

# token配置
token:
    # 令牌自定义标识
    header: Authorization
    # 令牌密钥
    secret: abcdefghijklmnopqrstuvwxyz
    # 令牌有效期(默认30分钟)
    expireTime: 1440
    # 门户网站令牌有效期
    portalExpireTime: 0
1
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










 
 
 
 
 


/**
 * 刷新令牌有效期
 *
 * @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

# 修改认证过滤器





 
 








 
 
 
 
 
 
 
 
 
 
 
 
 
 
 



@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

# 修改退出处理类





 
 







 
 
 
 
 
 
 
 
 
 
 
 
 
 



@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

# 手机验证码登录

@Data
public class PortalLoginBody {
    @NotEmpty(message = "手机号不能为空")
    private String phone;
    private String code;
}
1
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
@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring()
            .antMatchers("/portal/getCode", "/portal/login");
}
1
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

获取用户信息:http://127.0.0.1:8080/portal/getInfo

参数名 参数值
Authorization Portal token

退出登录(没登录也能调用):http://127.0.0.1:8080/logout

上次更新: 2022-10-28 22:23:08