介绍
shiro 是一个功能强大和易于使用的Java安全框架,为开发人员提供一个直观而全面的解决方案的认证,授权,加密,会话管理。
主要功能:
- Authentication: 身份认证/登录,验证用户是不是拥有相应的身份;
- Authorization: 授权,即权限验证,判断某个已经认证过的用户是否拥有某些权限访问某些资源,一般授权会有角色授权和权限授权;
- SessionManager: 会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的,web 环境中作用是和 HttpSession 是一样的;
- Cryptography: 加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Spring Boot 集成 Shiro
Spring Boot 集成 shiro 其实也不难,只需要两个地方的配置:一个是 shiro 的配置类,一个是自定义的 Realm 类。
shiroConfig 配置类:就是对shiro的一些配置,相对于之前的xml配置。包括:过滤的文件和权限,密码加密的算法,其用注解等相关功能。
自定义的 Realm 类:自定义的CustomRealm继承AuthorizingRealm。并且重写父类中的doGetAuthorizationInfo(权限相关)、doGetAuthenticationInfo(身份认证)这两个方法。
好了,废话不多说,下面开始上代码:
1. 引入相关依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
2. 配置Shiro的核心过滤器
对应的就是 shiroConfig 配置类
@Configuration
public class ShiroFilterConf {
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//过滤器链的集合 AnonymousFilter 匿名过滤器 anon
//FormAuthenticationFilter 认证过滤器 authc
Map<String, String> map = new HashMap<>();
map.put("/admin/loginAdmin","anon");
map.put("/code/getCode","anon");
//放行login文件夹下的所有资源,有静态资源样式,不放行样式会消失
map.put("/login/**","anon");
map.put("/**","authc");
shiroFilterFactoryBean.setLoginUrl("/login/login.jsp");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager getSecurityManager( MyRealm myRealm,EhCacheManager ehCacheManager){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setCacheManager(ehCacheManager);
securityManager.setRealm(myRealm);
return securityManager;
}
@Bean
public MyRealm getMyRealm(CredentialsMatcher credentialsMatcher){
MyRealm myRealm = new MyRealm();
myRealm.setCredentialsMatcher(credentialsMatcher);
return myRealm;
}
@Bean
public CredentialsMatcher getCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 加密算法 和 散列次数
hashedCredentialsMatcher.setHashAlgorithmName("md5");
hashedCredentialsMatcher.setHashIterations(1024);
return hashedCredentialsMatcher;
}
@Bean
public EhCacheManager getEhCatch(){
EhCacheManager ehCacheManager = new EhCacheManager();
return ehCacheManager;
}
}
3. 自定义MyRealm
这里是自定义的 Realm 类,继承了 AuthenticatingRealm
//AuthorizingRealm 继承了 AuthenticatingRealm
public class MyRealm extends AuthorizingRealm {
@Autowired
private AdminService adminService;
@Override //授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("===================");
//通过用户名查主体 通过主体查角色 通过角色查权限
String principal = (String) principalCollection.getPrimaryPrincipal();
//查数据库
Map<String, Object> map = new HashMap<>();
map.put("name", principal);
List<Admin> admins = adminService.selectByMap(map);
if (admins.size() != 0) {
Admin admin = admins.get(0);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRole(admin.getLevel());
//如果是超级管理员 拥有删除用户的权利 这里这样写是因为前台用的 JqGrid <shiro:hasPermission name="user:delete">del:false,</shiro:hasPermission>
if ("super".equals(admin.getLevel())) {
authorizationInfo.addStringPermission("user:add");
authorizationInfo.addStringPermission("user:update");
authorizationInfo.addStringPermission("user:query");
}else{
authorizationInfo.addStringPermission("user:add");
authorizationInfo.addStringPermission("user:delete");
authorizationInfo.addStringPermission("user:update");
authorizationInfo.addStringPermission("user:query");
}
return authorizationInfo;
}
return null;
}
@Override //认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String principal = (String) authenticationToken.getPrincipal();
//查数据库 获取User对象 判断user对象是否为空 不为空 封装一个AuthenticationInfo返回
//查数据库
Map<String, Object> map = new HashMap<>();
map.put("name", principal);
List<Admin> admins = adminService.selectByMap(map);
if (admins.size() != 0) {
Admin admin = admins.get(0);
AuthenticationInfo authenticationInfo =
new SimpleAuthenticationInfo(admin.getName(), admin.getPassword(), ByteSource.Util.bytes(""), this.getName());
return authenticationInfo;
}
return null;
}
}
4. Controller 中
//shiro登录验证
@RequestMapping("loginAdmin")
public Map<String,Object> LoginUser(String username, String password, String code, HttpServletRequest request) {
//获得验证码
String validationCode = (String) request.getSession().getAttribute("code");
if (!validationCode.equalsIgnoreCase(code)) {
return setResultErrorMsg("验证码错误");
}
//shiro判断用户名和密码
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
Map<String, Object> map = BaseApiService.setResultSuccess();
return map;
} catch (UnknownAccountException e) {
System.out.println("用户名不正确");
return setResultErrorMsg("用户名不正确");
} catch (IncorrectCredentialsException e) {
System.out.println("密码错误");
return setResultErrorMsg("密码错误");
}
}
//退出时shiro清除登录session
@RequestMapping("logoutAdmin")
public String LogoutUser() {
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "ok";
}
5. Shiro 的部分常用标签
<shiro:principal></shiro:principal> //用户的身份信息
<shiro:authenticated></shiro:authenticated> //认证成功 执行标签体的内容
<shiro:notAuthenticated></shiro:notAuthenticated> //未认证 执行标签体内容
//基于角色的权限管理
<shiro:hasRole name="super"></shiro:hasRole>
<shiro:hasAnyRoles name="admin,super"></shiro:hasAnyRoles>
//基于资源的权限管理
<shiro:hasPermission name="user:delete"></shiro:hasPermission>