Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。
Shiro 授权过程跟认证过程大致相似,下面我们仍然通过代码来熟悉一下过程(引入包类似这里节约篇幅就不贴出来了):
public class AuthenticationTest { SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm(); @Before // 在方法开始前添加一个用户,让它具备admin和user两个角色 public void addUser() { simpleAccountRealm.addAccount("wmyskxz", "123456", "admin", "user"); } @Test public void testAuthentication() { // 1.构建SecurityManager环境 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(simpleAccountRealm); // 2.主体提交认证请求 SecurityUtils.setSecurityManager(defaultSecurityManager); // 设置SecurityManager环境 Subject subject = SecurityUtils.getSubject(); // 获取当前主体 UsernamePasswordToken token = new UsernamePasswordToken("wmyskxz", "123456"); subject.login(token); // 登录 // subject.isAuthenticated()方法返回一个boolean值,用于判断用户是否认证成功 System.out.println("isAuthenticated:" + subject.isAuthenticated()); // 输出true // 判断subject是否具有admin和user两个角色权限,如没有则会报错 subject.checkRoles("admin","user"); // subject.checkRole("xxx"); // 报错 } }运行测试,能够正确看到效果。
自定义 Realm从上面我们了解到实际进行权限信息验证的是我们的 Realm,Shiro 框架内部默认提供了两种实现,一种是查询.ini文件的IniRealm,另一种是查询数据库的JdbcRealm,这两种来说都相对简单,感兴趣的可以去瞄两眼,我们着重就来介绍介绍自定义实现的 Realm 吧。
有了上面的对认证和授权的理解,我们先在合适的包下创建一个【MyRealm】类,继承 Shirot 框架的 AuthorizingRealm 类,并实现默认的两个方法:
package com.wmyskxz.demo.realm; import org.apache.shiro.authc.*; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import java.util.*; public class MyRealm extends AuthorizingRealm { /** * 模拟数据库数据 */ Map<String, String> userMap = new HashMap<>(16); { userMap.put("wmyskxz", "123456"); super.setName("myRealm"); // 设置自定义Realm的名称,取什么无所谓.. } /** * 授权 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { String userName = (String) principalCollection.getPrimaryPrincipal(); // 从数据库获取角色和权限数据 Set<String> roles = getRolesByUserName(userName); Set<String> permissions = getPermissionsByUserName(userName); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.setStringPermissions(permissions); simpleAuthorizationInfo.setRoles(roles); return simpleAuthorizationInfo; } /** * 模拟从数据库中获取权限数据 * * @param userName * @return */ private Set<String> getPermissionsByUserName(String userName) { Set<String> permissions = new HashSet<>(); permissions.add("user:delete"); permissions.add("user:add"); return permissions; } /** * 模拟从数据库中获取角色数据 * * @param userName * @return */ private Set<String> getRolesByUserName(String userName) { Set<String> roles = new HashSet<>(); roles.add("admin"); roles.add("user"); return roles; } /** * 认证 * * @param authenticationToken 主体传过来的认证信息 * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 1.从主体传过来的认证信息中,获得用户名 String userName = (String) authenticationToken.getPrincipal(); // 2.通过用户名到数据库中获取凭证 String password = getPasswordByUserName(userName); if (password == null) { return null; } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("wmyskxz", password, "myRealm"); return authenticationInfo; } /** * 模拟从数据库取凭证的过程 * * @param userName * @return */ private String getPasswordByUserName(String userName) { return userMap.get(userName); } }然后我们编写测试类,来验证是否正确:
import com.wmyskxz.demo.realm.MyRealm; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.subject.Subject; import org.junit.Test; public class AuthenticationTest { @Test public void testAuthentication() { MyRealm myRealm = new MyRealm(); // 实现自己的 Realm 实例 // 1.构建SecurityManager环境 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(myRealm); // 2.主体提交认证请求 SecurityUtils.setSecurityManager(defaultSecurityManager); // 设置SecurityManager环境 Subject subject = SecurityUtils.getSubject(); // 获取当前主体 UsernamePasswordToken token = new UsernamePasswordToken("wmyskxz", "123456"); subject.login(token); // 登录 // subject.isAuthenticated()方法返回一个boolean值,用于判断用户是否认证成功 System.out.println("isAuthenticated:" + subject.isAuthenticated()); // 输出true // 判断subject是否具有admin和user两个角色权限,如没有则会报错 subject.checkRoles("admin", "user"); // subject.checkRole("xxx"); // 报错 // 判断subject是否具有user:add权限 subject.checkPermission("user:add"); } }运行测试,完美。
Shiro 加密