理论:
三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>${shiro}</version>
</dependency>
ShiroConfiguration .java
@Configuration
@ConditionalOnProperty(name = "shiro.web.enabled", matchIfMissing = true)
public class ShiroConfiguration {
@Bean
public SubjectFactory subjectFactory() {
return new AccountSubjectFactory();
}
@Bean
public Realm accountRealm() {
return new AccountRealm();
}
@Bean
public CacheManager shiroCacheManager(net.sf.ehcache.CacheManager cacheManager) {
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManager(cacheManager);
return ehCacheManager;
}
/**
* Shiro的过滤器链
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
shiroFilter.setLoginUrl("/login");
shiroFilter.setSuccessUrl("/");
shiroFilter.setUnauthorizedUrl("/error/reject.html");
HashMap<String, Filter> filters = new HashMap<>();
filters.put("authc", new AuthenticatedFilter());
shiroFilter.setFilters(filters);
/**
* 配置shiro拦截器链
*
* anon 不需要认证
* authc 需要认证
* user 验证通过或RememberMe登录的都可以
*
* 顺序从上到下,优先级依次降低
*
*/
Map<String, String> hashMap = new LinkedHashMap<>();
hashMap.put("/dist/**", "anon");
hashMap.put("/theme/**", "anon");
hashMap.put("/storage/**", "anon");
hashMap.put("/login", "anon");
hashMap.put("/ljh", "anon");
hashMap.put("/user/**", "authc");
hashMap.put("/settings/**", "authc");
hashMap.put("/post/editing", "authc");
hashMap.put("/post/submit", "authc");
hashMap.put("/post/delete/*", "authc");
hashMap.put("/post/upload", "authc");
hashMap.put("/admin/channel/list", "authc,perms[channel:list]");
hashMap.put("/admin/channel/update", "authc,perms[channel:update]");
hashMap.put("/admin/channel/delete", "authc,perms[channel:delete]");
shiroFilter.setFilterChainDefinitionMap(hashMap);
return shiroFilter;
}
}
AccountRealm.java
public class AccountRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private UserRoleService userRoleService;
public AccountRealm() {
super(new AllowAllCredentialsMatcher());
setAuthenticationTokenClass(UsernamePasswordToken.class);
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
AccountProfile profile = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
if (profile != null) {
UserVO user = userService.get(profile.getId());
if (user != null) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
List<Role> roles = userRoleService.listRoles(user.getId());
//赋予角色
roles.forEach(role -> {
info.addRole(role.getName());
//赋予权限
role.getPermissions().forEach(permission -> info.addStringPermission(permission.getName()));
});
return info;
}
}
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
AccountProfile profile = getAccount(userService, token);
if (null == profile) {
throw new UnknownAccountException(upToken.getUsername());
}
if (profile.getStatus() == Consts.STATUS_CLOSED) {
throw new LockedAccountException(profile.getName());
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(profile, token.getCredentials(), getName());
Session session = SecurityUtils.getSubject().getSession();
session.setAttribute("profile", profile);
return info;
}
protected AccountProfile getAccount(UserService userService, AuthenticationToken token) {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
return userService.login(upToken.getUsername(), String.valueOf(upToken.getPassword()));
}