# 功能描述

实现登录及退出操作。
配置文件为application-login.yml

提示

(1) 需在application.yml中增加spring.profiles.active中增加login才能激活配置文件
(2) 需设置application-login.yml中的sei.cloud.login.enabled为true才能开启login服务

# 配置一览表

sei:
  cloud:
    login:
      enabled: true #设置为true才开启login服务
      pass-url: /*/public/** #不拦截的url(不验证登录),多个url以逗号分隔
      check-code: abcd #万能验证码
      sso:
        enabled: false #设置为true才开启sso登录服务
        ip: 127.0.0.1  #允许发出sso登录的服务器IP地址,多个ip之间用逗号分隔
        home: /#/dashboard #验证成功后的跳转地址
        login: /noPrivilege.html #验证不成功的跳转地址

      web:  #web项目登录配置
        master: #默认的主项目
          name: master #主项目名称
          register: true  #是否允许web端注册,true:允许注册,false:关闭注册
          register-sysid: sys #web注册人员所属系统编号
          register-rid: #web注册人员的默认角色编号
          register-oid: #web注册人员的默认部门编号
          register-login: false #web注册后是否允许立即登录
          timeout: 1900 #过期时间(秒)
          jwt-key:  qwiuery723shdb654A5&^&*^&*^%$+_)&^%$#$RDFCVBNURDFCVBN #jwt的秘钥,如果不配置本项,则系统采用session验证
#        slave: #其它的web项目配置
#        - name: slave1 #自定义名称(注意:名称不能与其它项目的名称重复)
#          online: false  #是否记录在线用户列表
#          multiple: false #是否允许1个账号多个地方使用web同时登录,(为true的时候必须使用session,不能使用jwt)
#          register: true  #是否允许web端注册,true:允许注册,false:关闭注册
#          register-rid: #web注册人员的默认角色编号
#          register-validation: 0  #注册时候验证码类型,0:不要验证,1:手机短信验证,2:web系统本身产生的验证码验证
#          timeout: 800 #过期时间(秒)
#          jwt-key:  qwiuery723shdb654A5&^&*^&*^%$+_)&^%$#$RDFCVBNURDFCVBN #jwt的秘钥,如果不配置本项,则系统采用session验证
#        - name: slave2 #自定义名称(注意:名称不能与其它微信的名称重复)
#          online: false  #是否记录在线用户列表
#          multiple: false #是否允许1个账号多个地方使用web同时登录,(为true的时候必须使用session,不能使用jwt)
#          register: true  #是否允许web端注册,true:允许注册,false:关闭注册
#          register-rid: #web注册人员的默认角色编号
#          register-validation: 0  #注册时候验证码类型,0:不要验证,1:手机短信验证,2:web系统本身产生的验证码验证
#          timeout: 800 #过期时间(秒)
#          jwt-key: hljqwherjqh1234jhasKJHKHJgUY877UYouyihg #jwt的秘钥,如果不配置本项,则系统采用session验证

#      weixin: #微信登录及支付配置
#        master: #默认微信的配置
#          name: master #自定义名称(注意:名称不能与其它微信的名称重复)
#          appid:  #微信appid
#          secret:  #微信安全码
#          apikey:
#          mchid: 1538025081 #商户号(支付用)
#          notify-url: http://127.0.0.1/api/weixin/notify #微信支付后的回调url(支付用)
#          cache: 0 #缓存微信返回的access_token时间,秒为单位
#          register: false #是否作为新用户增加到sys_user用户表中(在没有写该项目loginEvent继承类的weixin_register方法时才有用)
#        slave: #其它微信的配置
#        - name: slave1 #自定义名称(注意:名称不能与其它微信的名称重复)
#          appid:  #微信appid
#          secret:  #微信安全码
#          mchid:  #商户号
#          cache: 0 #缓存微信返回的access_token时间,秒为单位
#          register: false #是否作为新用户增加到sys_user用户表中
#        - name: slave2 #自定义名称(注意:名称不能与其它微信的名称重复)
#          appid:  #微信appid
#          secret:  #微信安全码
#          mchid:  #商户号
#          cache: 0 #缓存微信返回的access_token时间,秒为单位
#          register: false #是否作为新用户增加到sys_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

# Service接口

# 第一步 引入包

<dependency>
    <groupId>sei-cloud</groupId>
    <artifactId>login</artifactId>
</dependency>
1
2
3
4

# 第二步 引入接口

@Resource
    LoginService loginService;
1
2

# 第三步 使用接口

/**
 * 系统用户、账户相关服务API
 * @author xiong
 */
public interface LoginService {
    /**
     * 获得系统数据账套
     * @return List
     */
    List<Map> getDbList();

    /**
     * 设置验证码
     * @param projectName: 项目编号(与配置文件中项目名称对应,为null则表示主项目或缺省项目)
     */
    void setCheckCode(@NonNull String projectName);

    /**
     * 检测验证码是否正确
     * @param checkCode: 用户输入的验证码(abcd代表不用验证)
     * @return 验证正确返回true, 验证错误返回false
     */
    boolean verificationCheckCode(@NonNull String checkCode);

    /**
     * 判断用户是否登录
     * @return boolean
     */
    boolean isLogin();

    /**
     * 延长用户在线时长
     * @param projectName: 项目名称(与配置文件中项目名称对应,为null则表示主项目或缺省项目)
     * @return ResMsg
     * @throws IllegalArgumentException 异常
     * @throws IllegalAccessException 异常
     */
    ResMsg online(@Nullable String projectName) throws IllegalArgumentException, IllegalAccessException;

    /**
     * 统一认证成功后调用登录
     * @param dbKey: 数据库账套编号
     * @param projectName: 项目编号
     * @param uid: 用户编号
     * @return ResMsg
     */
    ResMsg ssoLogin(@Nullable String dbKey, @Nullable String projectName, @NonNull String uid);

    /**
     * 登录系统, os参数意义: 1:androd, 2:ios, 3:微信 除此之外为web
     * @param json: 内容
     * @return ResMsg
     * @throws SQLException 异常
     * @throws IllegalArgumentException 异常
     * @throws IllegalAccessException 异常
     */
    ResMsg login(@NonNull JSONObject json) throws SQLException, IllegalArgumentException, IllegalAccessException;

    /**
     * 退出系统
     * @return ResMsg
     * @throws IllegalArgumentException 异常
     * @throws IllegalAccessException 异常
     */
    ResMsg logout() throws IllegalArgumentException, IllegalAccessException;

    /**
     * 校验用户账号及口令
     * @param dbKey: 数据库账套
     * @param uid: 用户账号
     * @param password: 用户口令
     * @param resMsg: 检验失败返回的错误代码及提示信息
     * @param verificationPassword: 是否验证口令(用于单点登录时不验证口令)
     * @return SessionUser:校验成功后的用户信息
     * @throws SQLException 异常
     */
    SessionUser verificationUser(@NonNull String dbKey, @NonNull String uid, @NonNull String password, @NonNull ResMsg resMsg, boolean verificationPassword) throws SQLException;

    /**
     * 日志记录并缓存权限
     * @param sessionUser: session用户信息
     */
    void logAndCachePrivilege(@NonNull SessionUser sessionUser);

    /**
     * 检查并获得项目名称
     * @param projectName: projectName
     * @param defaultVal: 缺省值
     * @return String 项目名称
     */
    String getProjectName(@Nullable String projectName, @NonNull String defaultVal);

    /**
     * 获得web缺省项目编号
     * @return String
     */
    String getDefaultWebProjectName();

    /**
     * 获得微信缺省项目编号
     * @return String
     */
    String getDefaultWeiXinProjectName();

    /**
     * 获得微信缺省项目编号
     * @return String
     */
    String getDefaultAliPayProjectName();

    /**
     * 获得WEB配置信息
     * @param projectName: web项目名称
     * @return JSONObject
     */
    JSONObject getWebConfig(@Nullable String projectName);

    /**
     * 获得微信配置信息
     * @param projectName: 微信项目名称
     * @return JSONObject
     */
    JSONObject getWeixinConfig(@Nullable String projectName);

    /**
     * 获得支付宝配置信息
     * @param projectName: 支付宝项目名称
     * @return JSONObject
     */
    JSONObject getAliPayConfig(@Nullable String projectName);

    /**
     * 返回用户访问的IP地址
     * @return String
     */
    String getIp();

    /**
     * 创建token
     * @param dbKey: 数据库账套编号,单数据库可以不设置
     * @param projectName: 项目名称(为null则表示主项目或缺省项目)
     * @param user: 用户
     * @param timeOut: 过期时间,单位:秒
     * @param attKeyVal: 附加值,是键值对
     * @return String
     * @throws IllegalArgumentException 异常
     * @throws IllegalAccessException 异常
     */
    String createToken(@Nullable String dbKey, @Nullable String projectName, @NonNull SessionUser user, int timeOut, Object... attKeyVal) throws IllegalArgumentException, IllegalAccessException;

    /**
     * 解析JWT
     * @param token: token
     * @return Claims
     */
    Claims parseJWT(@NonNull String token);

    /**
     * 检测账号和邮箱是否存在,如果成功则向邮箱发送更改密码的链接地址
     * @param json: 内容
     * @return ResMsg
     * @throws SQLException 异常
     * @throws MessagingException 异常
     */
    ResMsg checkAndSendEmail(@NonNull JSONObject json) throws SQLException, MessagingException;

    /**
     * 检测更改密码的链接地址有效性
     * @param json: 内容
     * @return ResMsg
     */
    ResMsg checkPasswordUrl(@NonNull JSONObject json);

    /**
     * 通过链接地址重置新密码
     * @param json: 内容
     * @return ResMsg
     * @throws SQLException 异常
     */
    ResMsg resetPassword(@NonNull JSONObject json) throws SQLException;

    /**
     * 用户注册
     * @param json: 用户注册数据
     * @return ResMsg
     * @throws Exception 异常
     */
    ResMsg register(@NonNull Object json) throws Exception;

    /**
     * 获取微信接口凭据
     * @param projectName: 微信项目名称(为空则采用默认配置)
     * @param code: 微信code
     * @return JSONObject
     */
    JSONObject getWeixinAccessToken(@Nullable String projectName, @NonNull String code);

    /**
     * 校验微信token
     * @param access_token: 微信token
     * @param openid: 微信openid
     * @return JSONObject
     */
    JSONObject getWeixinValidateData(@NonNull String access_token, @NonNull String openid);

    /**
     * 获得刷新后的token
     * @param projectName: 微信项目名称(为空则采用默认配置)
     * @param refresh_token: 微信refresh_token
     * @return JSONObject
     */
    JSONObject getWeixinRefreshToken(@Nullable String projectName, String refresh_token);

    /**
     * 获得微信用户信息
     * @param access_token: 微信token
     * @param openid: 微信openid
     * @return JSONObject
     */
    JSONObject getWeixinUserInfo(@NonNull String access_token, @NonNull String openid);
}
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

# Controller接口


@ConditionalOnProperty(name = "sei.cloud.login.enabled", havingValue = "true")
@Api(description = "登录等服务")
@RequestMapping(value = "/api")
public class LoginController {

    @ConditionalOnProperty(name = "sei.cloud.login.sso.enabled", havingValue = "true")
    @ApiOperation(value = "sso登录")
    @RequestMapping(value = "/public/ssoLogin",method = {RequestMethod.GET},produces = { MediaType.APPLICATION_JSON_VALUE })
    public void ssoLogin(@RequestParam(required = false) String uid, @RequestParam(required = false) String home, @RequestParam(required = false) String login) throws Exception;

    @ApiOperation(value = "延长在线时长",response = ResMsg.class)
    @RequestMapping(value = "/user/online",method = {RequestMethod.GET},produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody ResMsg online(@RequestParam(required = false) String projectName) throws Exception;

    @ApiOperation(value = "登录服务",response = ResMsg.class)
    @RequestMapping(value = "/public/login",method = {RequestMethod.POST},produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody ResMsg login(@RequestBody JSONObject json) throws SQLException, IllegalArgumentException, IllegalAccessException;

    @ApiOperation(value = "登出服务",response = ResMsg.class)
    @RequestMapping(value = "/logout",method = {RequestMethod.POST},produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody ResMsg logout() throws Exception;

    @ApiOperation(value = "获得服务器账套",response = ResMsg.class)
    @RequestMapping(value = "/public/dbList",method = {RequestMethod.GET},produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody List<Map> getDbList();

    @ApiOperation(value = "语言切换",response = ResMsg.class)
    @RequestMapping(value = "/public/i18n",method = {RequestMethod.POST}, produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody ResMsg i18n(@RequestParam(required = true)@ApiParam(value = "语言", required = true) String i18n);

    @ApiOperation(value = "获得验证码")
    @RequestMapping(value = "/public/checkCode",method = {RequestMethod.GET}, produces = { MediaType.APPLICATION_JSON_VALUE })
    public void setCheckCode(@RequestParam(required = false) String name);

    @ApiOperation(value = "检查邮箱并发送更改密码的链接地址")
    @RequestMapping(value = "/public/checkAndSendEmail",method = {RequestMethod.POST},produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody ResMsg checkAndSendEmail(@RequestBody JSONObject json) throws Exception;

    @ApiOperation(value = "检查更改密码的连接地址有效性")
    @RequestMapping(value = "/public/checkPasswordUrl",method = {RequestMethod.POST},produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody ResMsg checkPasswordUrl(@RequestBody JSONObject json) throws Exception;

    @ApiOperation(value = "重置密码")
    @RequestMapping(value = "/public/resetPassword",method = {RequestMethod.POST},produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody ResMsg resetPassword(@RequestBody JSONObject json) throws Exception;

    @ApiOperation(value = "用户注册")
    @RequestMapping(value = "/public/register",method = {RequestMethod.POST},produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody ResMsg register(@RequestBody Object json) throws Exception;
}
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

# 框架登录事件

使用时通过继承本类实现对操作成功的回调。

/**
 * 框架登录事件
 * @author xiong
 */
public abstract class LoginEvent {

    /**
     * 返回项目编号,注意项目编号必须与application-login.yml文件中项目属性值name值对应
     * @return String
     */
    public abstract String getProjectName();

    /**
     * 返回注册成功后的用户信息
     * 数据内容:{
     *   openid:
     *   access_token:
     *   refresh_token:
     *   unionid:
     *   nickname: 昵称
     *   headimgurl: 微信头像
     * }
     * @param userData: 微信回传的用户信息数据
     * @return SessionUser 成功后的SessionUser类型的用户信息,为null表示微信注册失败(注意返回的SessionUser必须设置uid和name的值)
     */
    public SessionUser weixin_register(JSONObject userData){
        return null;
    }

    /**
     * web用户登录验证(判断账号/口令等),替换默认的登录验证
     * @param dbKey: 数据库账套
     * @param uid: 用户账号
     * @param password: 用户口令
     * @param resMsg: 检验失败返回的错误代码及提示信息
     * @return: 校验成功后的SessionUser类型的用户信息,为null表示检验失败(注意返回的SessionUser必须设置uid和name的值)
     *          SessionUser必须对uid,name属性设置值
     */
    public SessionUser web_login_verif(String dbKey, String uid, String password, ResMsg resMsg){
        return null;
    }

    /**
     * web用户注册事件(替换默认的注册事件)
     * @param userData: 用户数据
     * @return: ResMsg | null
     */
    public ResMsg web_register(JSONObject userData){
        return null;
    }

    /**
     * 登录前的回调
     * @param projectName: 项目名称
     * @param os: 登录终端: 3:微信,0:web
     * @param json: 前端发回的数据
     */
    public void login_before(String projectName, int os, JSONObject json) {
    }

    /**
     * 登录校验成功后缓存用户信息之前的回调,用于扩展用户SessionUser并缓存到session中
     * @param projectName: 项目名称
     * @param sessionUser: session缓存的用户信息
     */
    public void login_verif_after(String projectName, SessionUser sessionUser) {
    }

    /**
     * 完成用户登录后的回调
     * @param projectName: 项目名称
     * @param os: 登录终端: 3:微信,0:web
     * @param sessionUser: session缓存的用户信息(注意这里修改了SessionUser只在本次请求有效,下次请求会丢失)
     */
    public void login_After(String projectName, int os, SessionUser sessionUser) {
    }

    /**
     * 完成用户退出后的回调
     * @param sessionUser: session中的用户信息
     */
    public void logOut(SessionUser sessionUser){
    }
}
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84