对比Spring Security
Spring Security,是一个基于Spring的身份验证和访问控制框架。支持主流的认证方式(HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等)。授权方面,提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制。
官网:https://spring.io/projects/spring-security
Apache Shiro,依赖性低,可以独立运行不依赖Spring,当然也可以容易地集成到Spring,属于轻量级框架。提供了包括认证、授权、加密、会话管理等功能。安全有时候是很复杂的,与Spring Security 相比,Shiro使用了比较简单易懂易于使用的授权方式。
官网:http://shiro.apache.org
Shiro框架体系
- Authentication(认证):用户身份识别,通常被称为用户“登录”。
- Authorization(授权):访问控制。比如某个用户是否具有某个操作的使用权限。
- Session Management(会话管理):特定于用户的会话管理,甚至在非web 应用程序。
- Cryptography(加密):在对数据源使用加密算法加密的同时,保证易于使用。
三个概念
- Subject:代表当前用户,可以是一个人,也可以是第三方服务。在单应用中,可将其视为User的同义词。
- SecurityManager:管理所有Subject,对于 Web 应用一般使用DefaultWebSecurityManager。
- Realms:用于进行权限信息的验证,我们自己实现。是一个执行者,负责真正的认证和鉴权。
我们需要实现Realms的Authentication 和 Authorization。其中 Authentication 是用来验证用户身份,Authorization是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。
Springboot集成
org.apache.shiro
shiro-spring
1.4.1
自定义认证器MyShiroRealm
添加MyShiroRealm并继承AuthorizingRealm,实现其中的两个方法。
doGetAuthenticationInfo:实现用户认证,通过服务加载用户信息并构造认证对象返回。
doGetAuthorizationInfo:实现权限认证,通过服务加载用户角色和权限信息设置进去。
/**
* 实现AuthorizingRealm接口用户用户认证
*/
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private LoginService loginService;
/**
* 用户认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
// 加这一步的目的是在Post请求的时候会先进认证,然后在到请求
if (authenticationToken.getPrincipal() == null) {
return null;
}
// 获取用户信息
String name = authenticationToken.getPrincipal().toString();
User user = loginService.findByName(name);
if (user == null) {
// 这里返回后会报出对应异常
return null;
} else {
// 这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name,
user.getPassword().toString(), getName());
return simpleAuthenticationInfo;
}
}
/**
* 角色权限和对应权限添加
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取登录用户名
String name = (String) principalCollection.getPrimaryPrincipal();
// 查询用户名称
User user = loginService.findByName(name);
// 添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (Role role : user.getRoles()) {
// 添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
for (Permission permission : role.getPermissions()) {
// 添加权限
simpleAuthorizationInfo.addStringPermission(permission.getPermission());
}
}
return simpleAuthorizationInfo;
}
}
添加Shiro配置类
配置路由的访问控制,以及注入自定义的认证器MyShiroRealm。
@Configuration
public class ShiroConfig {
// 将自己的验证方式加入容器
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
// 权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
// Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map filterMap = new HashMap();
// 登出
filterMap.put(/logout, logout);
// swagger
filterMap.put(/swagger**/**, anon);
filterMap.put(/webjars/**, anon);
filterMap.put(/v2/**, anon);
// 对所有用户认证
filterMap.put(/**, authc);
// 登录
shiroFilterFactoryBean.setLoginUrl(/login);
// 首页
shiroFilterFactoryBean.setSuccessUrl(/index);
// 错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl(/error);
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
// 加入注解的使用,不加入这个注解不生效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
LoginController
/**
* POST登录
*/
@PostMapping(value = /login)
public String login(@RequestBody User user) {
// 添加用户认证信息
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getName(), user.getPassword());
SecurityUtils.getSubject().login(usernamePasswordToken);
return login ok!;
}
一个简单的Shiro集成,已经完成了。其它User,Role,Dao比较基础的省略不占篇幅了。
启动springboot,提交/login接口username,password验证。