博主是一个刚步入北漂的低级码农,具体就不多说了,开车。
能知道shiro,看到此篇文章的,估计绝大多数都是像我一样被老大安排开发权限那一块的功能的搬砖萌新。
google、百度了半天,看了大量shiro的入门教程。随后带着一脸懵逼...
开发环境是spring全家桶系列还好,如果像我一样,开发环境完全是其他底层(我们是netty)的,基本上就GG了。
毕竟我只需要shiro的后台的某一些功能,没必要用那些花里胡哨的= =。
故而,本篇博文的编辑,其实就为了给GG的同行,行一个不算方便的方便。
需要的东西:
JDK(我用的是通用的1.8)
一个依赖管理工具(我用的是gradle)
ide(我的是idea)
--------------华丽的分割线--------------------
依赖速成的话就一个,权限的开发足够用了
gradle:
compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.4.0'
Maven:
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
版本的话用的是不新不旧的,想要自己找去这个网站搜索:https://mvnrepository.com/ 这个网站是后台媛与猿的神器,不解释。
---------分割线-----------
依赖弄好了之后,我们首先弄清楚的是三个东西。
Realm、SecurityManager、Subject 这三个是shiro在后台的绝对的核心。
Realm实际上就是存储着权限、角色的DB对象,SecurityManager则是管理者,Subject 则是对应的用户
(1)Realm:
Realm是一个接口,需要我们去实现,而shiro自带了一些实现Realm的基础class,为了更加适用绝大多数人,我们就略过了。
首先,我们先看如下这个实现逻辑
public class DatabaseRealm extends AuthorizingRealm {
/**
* 获取账号的角色、资源
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//能进入到这里,表示账号已经通过验证了
String userName = (String) principalCollection.getPrimaryPrincipal();
//根据userName获取该账户拥有的角色(这个逻辑自己用自己的数据库搞定)
Set<String> setRoles = getRolesByUserName(userName);
//根据角色获取该账户拥有的资源(这个也是,自己用自己的数据库搞定)
Set<String> setPermissions = getPermissionsByRoles(setRoles);
//授权对象
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//把获取到的角色和资源放进去
info.setStringPermissions(setPermissions);
info.setRoles(setRoles);
return info;
}
/**
* 根据token验证账户登录
*
* @param token
* @return 认证信息
* @throws AuthenticationException 如果登录失败,抛出这个错误
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//根据token获取认证的账号密码
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String userName = token.getPrincipal().toString();
String password = new String(usernamePasswordToken.getPassword());
//判断数据库中是存在该用户(这个逻辑自己从数据库中拿出来)
//(这个也自己搞定)
if (账号不存在) {
throw new AuthenticationException();
}
//认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userName, password, getName());
return info;
}
}
如上,我们一定要继承AuthorizingRealm ,达到实现Realm的目的,确保Realm能够根据username和password
从自己项目的数据库中拿出想要的角色、资源(权限)数据,中间自己实现的过程,就看各位项目中的数据库了。
(2)SecurityManager:
Realm实现后,我们有了通过自己的数据库获得权限,角色的对象,那么,就需要将对象给予
SecurityManager统一管理,再此看如下代码:
public class SecurityManager {
//初始化管理者(用它管控所有的权限判定)
public static final SecurityManager securityManager = SecurityManager.VOID();
//new一个对象 ^_^
public static SecurityManager VOID() {
return new SecurityManager();
}
private SecurityManager() {
//初始化
init();
}
//初始化
private void init() {
//初始化管理者
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//将数据库实现类绑定到管理者
defaultSecurityManager.setRealm(new DatabaseRealm());
//将 SecurityManager 实例绑定给 SecurityUtils
SecurityUtils.setSecurityManager(defaultSecurityManager);
}
//获取当前线程主题
private Subject getSubject() {
return SecurityUtils.getSubject();
}
//获取登录用的token
private UsernamePasswordToken getToken(String userName, String password) {
return new UsernamePasswordToken(userName, password);
}
//传入用户id,返回用户的Subject
private Subject getSubject(String username,String password) {
//获取主题
Subject subject = getSubject();
//认证登录
try {
subject.login(getToken(username,password));
} catch (AuthenticationException e) {
sout回车("用户验证身份时出现异常:" + e);
}
return subject;
}
//外部通用方法-判断用户是否为某个角色
public boolean isRole(String username,String password, String role) {
//获取用户身份subject
Subject subject = getSubject(username,password);
//判断角色
boolean isRole = subject.hasRole(role);
//登出
subject.logout();
return isRole;
}
//外部通用方法-判断用户是否拥有某个资源
public boolean isPermitted(String username,String password, String permission) {
//获取用户身份subject
Subject subject = getSubject(username,password);
//判断是否拥有资源
boolean isPermitted = subject.isPermitted(permission);
//登出
subject.logout();
return isPermitted;
}
}
咳咳 = =代码几乎都是手打的,可能有些错误,项目中引用的其他东西太多了,凑合着看。
其中 init()方法中的逻辑就是讲Realm的实现给予SecurityManager统一管理的初始化逻辑
(3)Subject :
一个subject对应一个用户(什么张三啊,李四啊)
刚才的代码中另外贴了Subject的应用,其中重要的有:
获取subject:SecurityUtils.getSubject();
//(获取subject是自带多线程的,不过一个线程只能有一个,切记,单线程的话多次获取,后一个会覆盖前一个)
登录认证:subject.login()
取消登录:subject.logout()
判断用户是否拥有角色: subject.hasRole(role);
判断用户是否拥有资源(权限):subject.isPermitted;
这些方法足够一个小中型项目完成后台的所有权限逻辑判断了,足够了,具体的详情网上一大堆,我就不多说了。
本章主要的精髓就是上面这两页代码,剩下的就是基于项目的业务代码了,shiro入门时候如果遇到瓶颈,本文绝对
会让你有所收获的。
----------------------------------------------
本人实在是太懒了= =就不多打了,框架这东西重在尝试,我只是提供一个思路~