shiroパーミッションフレームワークでは、ユーザーログインメソッドのsubject.login(token)は、カスタムUserNamePasswordRealmクラスのdoGetAuthenticationInfo認証メソッドに入ります。通常、doGetAuthenticationInfoは次のように記述されます。
/**
* 登录认证 subject.login()登录时调用
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//加这一步的目的是在Post请求的时候会先进认证,然后在到请求
UserToken user = (UserToken)authenticationToken;
if (authenticationToken.getPrincipal() == null) {
return null;
}
if (user == null) {
//这里返回后会报出对应异常
return null;
} else {
SysUser sysUser = null;
if (LoginTypeEnum.MANAGER.getType().equals(user.getCallType())) {
sysUser = userService.findByName(user.getUserName());
if(sysUser == null){
return null;
}
user.setSalt(sysUser.getSalt());
try {
Map<String, Object> map = getSysUserInfo(sysUser, 1);
String sysEmp = JSONObject.toJSONString(map);
user.setToken(map.get("token").toString());
user.setId(sysUser.getId());
user.setCompanyId(sysUser.getCompanyId());
user.setCompanyName(sysUser.getCompanyName());
redisUtil.set("ecommerece_sys" + "_" + sysUser.getId().toString(), sysEmp, 36000);
redisUtil.set("ecommerece_sys" + "_" + sysUser.getId().toString() + "_info", JSONObject.toJSONString(sysUser), 36000);
} catch (Exception e) {
e.printStackTrace();
}
}
//这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user, //用户
sysUser.getPassword(), //密码
ByteSource.Util.bytes(sysUser.getSalt()),//salt=username+salt
getName() //realm name
);
return authenticationInfo;
}
}
このメソッドではさまざまな論理的判断が行われますが、このメソッドdoGetAuthenticationInfo()の例外を次のようにカスタマイズしたいと思います。
if(!sysOrganization.getLoginScope().contains("1")){
throw new BusinessRuntimeException(Global.FORBIDDEN_ERROR, "您没有权限登录后台管理端,请联系管理员");
}
外部例外を正確にキャプチャできないことがわかりました。外部ログインによってキャッチされた例外は、AuthenticationException例外(IncorrectCredentialsExceptionおよびその他の例外の親クラス)として一律に書き換えられ、例外のmsgコンテンツも書き換えられます。
結論として
ソースコードはそれ自体のコードに問題がないため、外部はdoGetAuthenticationInfoメソッドによってスローされた例外をキャッチできません。
ソースコードを書き直す機能がない場合、さまざまな例外をキャッチしてフロントエンドにさまざまなプロンプトを表示するにはどうすればよいですか?
私の一時的な解決策は、doGetAuthenticationInfoはユーザー名とパスワードの確認にのみ使用され、認証例外は外部から直接キャプチャされることです。
カスタムBusinessRuntimeException例外など、その他のさまざまな検証がdoGetAuthenticationInfoメソッドからログインに移動され、doGetAuthenticationInfo()に入れて判断するのではなく、subject.login(userToken);に進む前に判断し、例外を与えます。
変更されたログインコードは次のとおりです。
@PostMapping("/login/anon")
@ApiResponses({ @ApiResponse(code = Global.SUCCESS, message = "成功!"),
@ApiResponse(code = Global.PARAM_ERROR, message = "参数错误!"),
@ApiResponse(code = Global.INTERNAL_SERVER_ERROR, message = "出错了!") })
@ApiOperation(value = "管理后台登录", httpMethod = "POST", notes = " 管理后台登录")
public SwaggerResultUtil<Object> login(HttpServletRequest request,@RequestBody User user) {
SwaggerResultUtil<Object> result = new SwaggerResultUtil<>();
//添加用户认证信息
Subject subject = SecurityUtils.getSubject();
UserToken userToken = new UserToken(
user.getUserName(),
user.getPassword(),
LoginTypeEnum.MANAGER.getType()
);
try {
SysUser sysUser = userService.findByName(user.getUserName());
if(sysUser.getAccountType()==3){
SysEmployee sysEmployee = sysEmployeeMapper.selectByAccount(user.getUserName());
SysOrganization sysOrganization = sysOrganizationMapper.selectByPrimaryKey(sysEmployee.getOrganizationId());
if(!sysOrganization.getLoginScope().contains("1")){
throw new BusinessRuntimeException(Global.FORBIDDEN_ERROR, "您没有权限登录后台管理端,请联系管理员");
}
}
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(userToken);
UserToken token= (UserToken) subject.getPrincipal();
token.setSalt(null);
token.setPassword(null);
result.setData(token);
result.setCode(Global.SUCCESS);
result.setMsg("登录成功");
//添加日志
SysLog sysLog=new SysLog();//自己写的日志类
String requestIp =request.getRemoteAddr();
sysLog.setOperatorIp(requestIp);
sysLog.setType(Byte.valueOf(LoginTypeEnum.MANAGER.getType()));
SysUser byName = sysUserMapper.findByName(user.getUserName());
sysLog.setOperatorName(byName.getName());
sysLog.setOperatorAccount(user.getUserName());
sysLog.setAction("管理后台登录");
sysLog.setCreateDate(System.currentTimeMillis());
sysLogMapper.insert(sysLog);
} catch (BusinessRuntimeException e){
e.printStackTrace();
result.setCode(Global.INTERNAL_SERVER_ERROR);
result.setMsg(e.getMsg());
return result;
} catch (AuthenticationException e) {
e.printStackTrace();
result.setCode(Global.INTERNAL_SERVER_ERROR);
result.setMsg("账号或密码错误!");
return result;
} catch (AuthorizationException e) {
e.printStackTrace();
result.setCode(Global.INTERNAL_SERVER_ERROR);
result.setMsg("没有权限!");
return result;
}
return result;
}