@Component
public class UserPhoneToken extends UsernamePasswordToken implements Serializable {
private static final long serialVersionUID = 6293390033867929958L;
// 手机号码
private String phoneNum;
//无参构造
public UserPhoneToken(){}
//获取存入的值
@Override
public Object getPrincipal() {
if (phoneNum == null) {
return getUsername();
} else {
return getPhoneNum();
}
}
@Override
public Object getCredentials() {
if (phoneNum == null) {
return getPassword();
}else {
return "ok";
}
}
public UserPhoneToken(String phoneNum) {
this.phoneNum = phoneNum;
}
public UserPhoneToken(final String userName, final String password) {
super(userName, password);
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
@Override
public String toString() {
return "PhoneToken [PhoneNum=" + phoneNum + "]";
}
}
4.2 在写shiroUserPhoneRealm,代码如下:
@Service
public class ShioUserPhoneRealm extends AuthorizingRealm {
@Autowired
private UserDao userDao;
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
//这儿的CredentialsMatcher的new的对象必须是AllowAllCredentialsMatcher
CredentialsMatcher matcher = new AllowAllCredentialsMatcher();
super.setCredentialsMatcher(matcher);
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 通过此方法完成认证数据的获取及封装,系统底层会将认证数据传递认证管理器,有认证管理器完成认证操作
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UserPhoneToken token = null;
if (authenticationToken instanceof UserPhoneToken) {
token = (UserPhoneToken) authenticationToken;
}else {
return null;
}
//获取我发送验证码是存入session中的验证码和手机号
String verificationCode = (String) SecurityUtils.getSubject().getSession().getAttribute("verificationCode");
String phone = (String) SecurityUtils.getSubject().getSession().getAttribute("phone");
//获取controller传过来的数据
String verificationCode1 = (String) token.getPrincipal();
//去数据库根据手机号查询用户信息
User user = userDao.findUserByUserPhone(phone);
if (StringUtils.isEmpty(verificationCode)) {
throw new ServiceException("网络错误");
}
//比对手机号
if (!verificationCode.equals(verificationCode1)) {
throw new ServiceException("验证码不正确");
}
if (user == null) {
throw new UnknownAccountException();
}
if (user.getState() == 0) {
throw new LockedAccountException();
}
return new SimpleAuthenticationInfo(user,phone,getName());
}
}
4.3 手机号码登录验证已经基本完成:controller代码如下:
@PostMapping("verificationCodeLogin")
@ResponseBody
public JsonResult verificationCodeLogin(String password) {
Subject subject = SecurityUtils.getSubject();
UserPhoneToken token = new UserPhoneToken(password);
subject.login(token);
return new JsonResult("login OK");
}
使用过程中遇到的bug
1.
org.apache.shiro.authc.UnknownAccountException: Realm [cn.tedu.wxacs.service.impl.ShioUserPhoneRealm@768d8431] was unable to find account data for the submitted AuthenticationToken [org.apache.shiro.authc.UsernamePasswordToken - 张三, rememberMe=false].
org.apache.shiro.authc.AuthenticationException: Authentication token of type [class org.apache.shiro.authc.UsernamePasswordToken] could not be authenticated by any configured realms. Please ensure that at least one realm can authenticate these tokens.
这儿出现的问题是应为我的ShioUserRealm的AuthenticationInfo方法的User user = userDao.findUserByUserName(username);这行代码出现的问题,debug的时候就发现这一句执行后就保错
原因:是因为我的application.yml文件中没有写dao对应的mapper文件的路径
3. 在ShioUserPhoneRealm的doGetAuthenticationInfo方法的new SimpleAuthenticationInfo(user,phone,getName())这个位置后就报错是应为ShioUserPhoneRealm的这个方法中你没有将new的对象设置为AllowAllCredentialsMatcher();
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
//这儿的CredentialsMatcher的new的对象必须是AllowAllCredentialsMatcher
CredentialsMatcher matcher = new AllowAllCredentialsMatcher();
super.setCredentialsMatcher(matcher);
}