引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.1</version>
</dependency>
Shiro配置类所用对象所属的包
import java.text.MessageFormat;
import java.util.List;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import com.tnr.scgcxx.base.CurrUser;
import com.tnr.scgcxx.model.Module;
import com.tnr.scgcxx.model.User;
import com.tnr.scgcxx.shiro.service.ShiroService;
开发集成Shiro配置类
@Configuration
public class ShiroConfigure {
private static final Logger LOG = LoggerFactory.getLogger(ShiroConfigure.class);
注册跨域过滤器
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter(){
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.setMaxAge(1L);
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
开发和配置安全数据源(Realm)
@Bean("authorizer")
@Autowired
public AuthorizingRealm saftyRealm(ShiroService shiroService) {
return new AuthorizingRealm() {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
CurrUser currUser = (CurrUser) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
List<Module> moduleList = shiroService.getModulesOfUser(currUser.getU_id());
for (Module module : moduleList) {
simpleAuthorizationInfo.addStringPermission(String.valueOf(module.getM_id()));
}
System.out.println("***********************");
System.out.println(currUser.getU_id()+"的权限->"+simpleAuthorizationInfo.getStringPermissions());
System.out.println("***********************");
return simpleAuthorizationInfo;
}
获取认证信息
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
String u_id = (String) token.getPrincipal();
User user = shiroService.getUser(u_id);
if (user == null) {
return null;
}
CurrUser currUser = new CurrUser(user.getU_id(),user.getU_name());
System.out.println("-------------------");
System.out.println(currUser.getU_name());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(currUser, user.getU_pwd(), this.getName());
System.out.println("************");
System.out.println(this.getName());
return info;
}};
}
配置Shiro过滤器拦截规则
@Bean @Autowired
public ShiroFilterChainDefinition shiroFilterChainDefinition(ShiroService shiroService) {
DefaultShiroFilterChainDefinition chainDefinition =
new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/css/**", "anon");
chainDefinition.addPathDefinition("/elementui/**", "anon");
chainDefinition.addPathDefinition("/js/**", "anon");
chainDefinition.addPathDefinition("/safty/login/**", "anon");
List<Module> moduleList = shiroService.getAllSubModules();
String PREMISSION_FORMAT = "authc,perms[{0}]";
//动态权限设置
for(Module module:moduleList) {
if(StringUtils.isEmpty(module.getM_url())) {
continue;
}
chainDefinition.addPathDefinition(module.getM_url().replace("index.html", "**"), MessageFormat.format(PREMISSION_FORMAT, String.valueOf(module.getM_id())));
}
//其它资源必须经过认证
chainDefinition.addPathDefinition("/**", "authc");
LOG.debug("=====Shiro安全规则=======================================================================");
LOG.debug(chainDefinition.getFilterChainMap().toString());
LOG.debug("=====Shiro安全规则=======================================================================");
return chainDefinition;
}
配置Shiro过滤器(starter方式下在application.properties中配置)
shiro:
loginUrl: /loginTo
successUrl: /successTo
unauthorizedUrl: /unauthorizedTo
非starter实现springboot和Shiro的集成(比starter集成多配置Shiro安全管理器和Shiro生命周期管理器)
配置Shiro安全管理器(SecurityManager)
@Bean
@Autowired
public org.apache.shiro.mgt.SecurityManager shiroSecurityManager(Realm realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
配置Shiro过滤器(非starter方式必须在Shiro配置文件中书写)
@Bean
@Autowired
public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager,ShiroFilterChainDefinition shiroFilterChainDefinition) throws Exception {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/loginTo");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedTo");
shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());
return shiroFilterFactoryBean;
}
配置Shiro生命周期管理器
@Bean
public org.apache.shiro.spring.LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new org.apache.shiro.spring.LifecycleBeanPostProcessor();
}
使用Shiro
- 编译ShiroService和ShiroDao以及mapper,并且在Springboot项目中扫描ShiroDao所在位置(使用@MapperScan({“package 1”,“package 1”})或者在其dao层直接使用@Mapper注解)
- 登录(用户认证)
@PostMapping("/user")
public Result login(@RequestBody UserDto userdto) {
try {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userdto.getU_id(),userdto.getU_pwd());
subject.login(usernamePasswordToken);
if(subject.isAuthenticated()) {
return Result.success("登录成功!!!");
}
return Result.fail("登录失败!!");
}catch(UnknownAccountException e) {
return Result.fail("用户名不存在!");
}catch (IncorrectCredentialsException e) {
return Result.fail("账户密码不正确!");
} catch (LockedAccountException e) {
return Result.fail("用户名被锁定 !");
}catch (Exception e) {
e.printStackTrace();
return Result.fail("系统升级中......");
}
}
- 安全退出
@DeleteMapping("/curruser")
public Result loginOut() {
SecurityUtils.getSubject().logout();
return Result.success("成功退出!!!");
}
- 修改密码
@PutMapping("/repair")
public Result repairPwd(@RequestBody String[] pwd) {
try {
homeService.repairPwd(pwd,getCurrUser());
SecurityUtils.getSubject().logout();
return Result.success("成功修改!!!");
}catch(BussnissException e) {
return Result.fail(e.getMessage());
}
}
- 授权处理(这里叫放行应该更合适,符合授权信息对象中的数据,则放行,否则无权限)
@Service
@Transactional
@CacheConfig(cacheNames = "home")
public class HomeServiceImpl implements HomeService{
@Autowired
private HomeDao homeDao;
@Override
@Cacheable(key="targetClass+'.'+methodName+'()'")
public List<MenuDto> getMenu(CurrUser currUser) {
正常获取菜单的代码
这里的获取菜单:仅仅只是为了将菜单显示到前端页面;
ShiroService的获取为了在用户访问菜单中的某一项内容是判断其有没有这个权限;
}
注解说明
@Cacheable()