跟GitLab,Jenkins,Docker打了一个多月交道,在Linux上各种安装服务,编写Shell脚本,感觉自己已经是个半专业的运维人员了。今天回归了一下代码, 看了一下8.8元系统的权限管理接口。认证和授权应该是所有系统开发中需要考虑的第一个问题,系统需要管理好用户,角色,权限等,需要提供登录,登出,注册等功能。8.8元系统使用了Shiro,在此对Shiro做一些理解。
- Subject: 请求发起的主体
- SecurityManager: 安全策略的实施主题
- Realm:安全策略的数据源,提供认证和授权信息
一个典型Realm的写法:
public class MyRealm extends AuthorizingRealm{
@Resource
private UserRepository userRepository;
@Resource
private RoleRepository roleRepository;
@Resource
private MenuRepository menuRepository;
/**
* 提供授权信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName=(String) SecurityUtils.getSubject().getPrincipal();
User user=userRepository.findByUserName(userName);
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
List<Role> roleList=roleRepository.findByUserId(user.getId());
Set<String> roles=new HashSet<String>();
for(Role role:roleList){
roles.add(role.getName());
List<Menu> menuList=menuRepository.findByRoleId(role.getId());
for(Menu menu:menuList){
info.addStringPermission(menu.getName()); // 添加权限
}
}
info.setRoles(roles);
return info;
}
/**
* 提供认证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String userName=(String)token.getPrincipal();
User user=userRepository.findByUserName(userName);
if(user!=null){
AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),"xxx");
return authcInfo;
}else{
return null;
}
}
}
当subject.login时,doGetAuthenticationInfo方法会被调用,用以检查是否时合法用户。
当标注有@RequiresPermissions的方法被调用时,doGetAuthorizationInfo方法会被调用,用以subject时候具有方法的调用权限。
subject的获取的相关源码,subject绑定在ThreadContext中,也从ThreadContext中获取,猜想Shiro会给每一个session单独的线程。
SecurityUtils.java:
public static Subject getSubject() {
Subject subject = ThreadContext.getSubject();
if (subject == null) {
subject = (new Subject.Builder()).buildSubject();
ThreadContext.bind(subject);
}
return subject;
}