自定义一个Realm,自定义Realm可以实现Realm接口,当然,根据自己的业务需求,也可以继承不同的父类,例如,我们需要实现认证功能,那么就可以继承AuthenticatingRealm,实现该接口的getAuthenticationInfo()方法。代码如下:
public class MyRealm extends AuthenticatingRealm {
/**
* 1.doGetAuthenticationInfo 获取认证信息,如果数据库中没有数据,返回null,如果得到正确的用户名和密码,返回指定类型对象
* 2.AuthenticationInfo是一个抽象接口,此处我们使用SimpleAuthenticationInfo,封装正确的用户名和密码
* @param authenticationToken 这是我们需要进行认证的令牌
* @return
* @throws AuthenticationException
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
SimpleAuthenticationInfo authenticationInfo=null;
//1.将token转化为UsernamePasswordToken
UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
//2.获取用户名
String username=token.getUsername();
//3.查询数据库中是否具有指定用户名和密码的用户
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/myblog?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=UTC","root","");
PreparedStatement ps=connection.prepareStatement("SELECT * FROM user WHERE login_id=?");
ps.setString(1,username);
ResultSet rs=ps.executeQuery();
if (rs.next()){
Object principal=username;
Object credential=rs.getObject(2);
String realmName=this.getName();
authenticationInfo=new SimpleAuthenticationInfo(principal,credential,realmName);
}else {
throw new AuthenticationException();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
//4.如果查询到了,那么封装查询结果,并返回结果
//5.如果没有查询到,则抛出异常
return authenticationInfo;
}
认证功能实现的原理
认证的过程中核心的过程是前台输入数据与后台数据库查询结果之间的比对,AuthenticatingRealm中有一个关键的成员属性,也就是
private CredentialsMatcher credentialsMatcher;
CredentialsMatcher 是一个接口,该接口中定义了一个方法:
boolean doCredentialsMatch(AuthenticationToken var1, AuthenticationInfo var2)
本案例中使用的是SimpleAuthenticationInfo,其所使用到的比对方法实现是SimpleCredentialsMatcher的:
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
Object tokenCredentials = this.getCredentials(token);
Object accountCredentials = this.getCredentials(info);
return this.equals(tokenCredentials, accountCredentials);
}
这里的token封装了前台传入的用户名密码,info则封装了数据库查询的结果。到这里,从前端页面到数据库的交互就完成了。