1.首先自建一个Demo上上手(用户登录认证)
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
@Before
public void AddUser(){
//手动创建了一个用户
simpleAccountRealm.addAccount("ljj","123");
}
@Test
public void testAuthentication(){
//1. 构建SecurityManager环境
DefaultSecurityManager manger = new DefaultSecurityManager();
manger.setRealm(simpleAccountRealm);//设置Realm环境
//2. 主体提交认证请求
SecurityUtils.setSecurityManager(manger);//设置SecurityManager环境
Subject subject = SecurityUtils.getSubject();//获得主体
UsernamePasswordToken token = new UsernamePasswordToken("ljj","123");
subject.login(token);//进行验证
//是否认证成功
System.out.println(subject.isAuthenticated());
//登出
subject.logout();
System.out.println(subject.isAuthenticated());
}
2.接着来一个用户角色认证
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
@Before
public void addUser(){
//添加用户和对应的权限
simpleAccountRealm.addAccount("ljj","123","admin","user");
}
@Test
public void testAuthentication(){
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(simpleAccountRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("ljj","123");
subject.login(token);
System.out.println(subject.isAuthenticated());
try {
//单个用checkRole
subject.checkRole("admin");
subject.checkRole("user");
// subject.checkRoles("admin", "user1");
System.out.println("cg");
}catch(Exception e){
System.out.println("不成功");
}
}
通过上面两个小案列,可以看到:
在用户登录和鉴权的时候,
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(simpleAccountRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("ljj","123"); subject.login(token);
这些操作是少不了的。反正就是根据得到的用户数据和本身存在的用户数据进行比对。一致就成功。不一致就抛出异常。
那么接下来目的就很明显了,既然可通过自建用户来鉴权用户。那么也可以通过在数据库中查询用户来进行比对。那么问题有来了,既然是去数据库中查询,那么鉴权的方式自然是需要自定义的了。因此,此处需要自定义Reaml。
public class RealmTest extends AuthorizingRealm {
/**
* 角色权限鉴定
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//1.从主体传过来的认证信息中,获取用户名
String userName = (String)principals.getPrimaryPrincipal();//获取用户名
Set<String> roles = new HashSet<>();
roles.add("admin");
roles.add("user");
Set<String> permission = new HashSet<>();
permission.add("url1");
permission.add("url2");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//设置权限
simpleAuthorizationInfo.setStringPermissions(permission);
//设置角色
simpleAuthorizationInfo.setRoles(roles);
return simpleAuthorizationInfo;
}
/**
* 用户登录鉴定
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//此为标准写法,token.getPrincipal();拿到的就是前面用户传过来得用户名
String userName = (String)token.getPrincipal();
String password = "123";//此处应该从数据库中获取密码
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName,password,"customRealm");
return simpleAuthenticationInfo;
}
很明显的可以看到,自定义的类必须继承AuthorizingRealm,然后重写它的两个方法:doGetAuthorizationInfo和doGetAuthenticationInfo。在doGetAuthenticationInfo中,我们进行用户登录鉴定;在doGetAuthorizationInfo中,我们进行
角色权限鉴定。有了这个自定义的Realm之后,我们再去进行验证。
@Test
public void testTestAuthentication(){
RealmTest realmTest = new RealmTest();
//构建SecurityManager环境
DefaultSecurityManager manger = new DefaultSecurityManager();
manger.setRealm(realmTest);
SecurityUtils.setSecurityManager(manger);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("ljj","123");
subject.login(usernamePasswordToken);
System.out.println(subject.isAuthenticated());
try {
subject.checkRole("admin");
}catch(Exception e){
System.out.println("没有这个角色");
}
try{
subject.checkPermission("url3");
}catch(Exception e){
System.out.println("没有这个url权限");
}
}
可以看到:
//构建SecurityManager环境
DefaultSecurityManager manger = new DefaultSecurityManager();
manger.setRealm(realmTest);
SecurityUtils.setSecurityManager(manger);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("ljj","123");
subject.login(usernamePasswordToken);
这些代码仍然是必须的,但是,在这些代码之前,加上了
RealmTest realmTest = new RealmTest();
这说明,我们需要把之前定义好的Realm,重新放入SecurityManager环境。
当程序走进subject.login(usernamePasswordToken);的时候,会先进入
doGetAuthenticationInfo方法,然后再进入
doGetAuthorizationInfo。也就是说,用户登录先鉴定,然后再进行角色和权限的鉴定。其中,login方法是怎么走到这两个方法里面的,此处暂不作调查。只需记住此类操作规范即可。后续会逐步研究shiro的底层,然后逐一解惑。
注意:如果操作数据库来验证的话,必须要配合shrioConfig来使用。因为操作Dao层得先加载Bean。
这是非常需要注意的