1.pom文件
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--shrio和thymeleaf集成的扩展依赖,为了能在页面上使用xsln:shrio的标签 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.自定义Realm
@Slf4j
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private RoleService roleService;//角色模模块
@Autowired
private UserService userService;//用户模块
@Autowired
private PermissionService permissionService;//权限模块
@Override
public String getName() {
return "myShiroRealm";
}
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
SysUser user = (SysUser) principals.getPrimaryPrincipal();
if (user == null) {
log.error("授权失败,用户信息为空!!!");
return null;
}
try {
//获取用户角色集
Set<String> listRole= roleService.findRoleByUsername(user.getUsername());
simpleAuthorizationInfo.addRoles(listRole);
//通过角色获取权限集
for (String role : listRole) {
Set<String> permission= permissionService.findPermissionByRole(role);
simpleAuthorizationInfo.addStringPermissions(permission);
}
return simpleAuthorizationInfo;
} catch (Exception e) {
log.error("授权失败,系统内部错误!!!", e);
}
return simpleAuthorizationInfo;
}
/**
* 登录
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken authToken = (UsernamePasswordToken) token;
// 获取用户输入的账号
String userName = authToken.getUsername();
//通过账号查找用户信息
SysUser user = userService.selectUserOne(userName);
if (null == user){
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user,
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
getName());
return authenticationInfo;
}
}
3.shiro的配置类
@Configuration
public class ShiroConfig {
/**
* 密码匹配凭证管理器(密码加密需要此配置)
* @return
*/
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
hashedCredentialsMatcher.setHashIterations(1);// 设置加密次数
return hashedCredentialsMatcher;
}
//配置自定义的Realm
@Bean
public MyShiroRealm myShiroRealm(HashedCredentialsMatcher matcher){
MyShiroRealm myShiroRealm= new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(matcher);
return myShiroRealm;
}
//将Realm注册到securityManager中
@Bean
public DefaultWebSecurityManager securityManager(MyShiroRealm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
//如果没有此name,将会找不到shiroFilter的Bean
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login"); //表示指定登录页面
shiroFilterFactoryBean.setSuccessUrl("/user/list"); // 登录成功后要跳转的链接
shiroFilterFactoryBean.setUnauthorizedUrl("/error"); //未授权页面
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();//拦截器, 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/login","anon"); //所有匿名用户均可访问到Controller层的该方法下
filterChainDefinitionMap.put("/userLogin","anon");
filterChainDefinitionMap.put("/image/**","anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/fonts/**","anon");
filterChainDefinitionMap.put("/js/**","anon");
filterChainDefinitionMap.put("/logout","logout");
filterChainDefinitionMap.put("/**", "authc"); //authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
//filterChainDefinitionMap.put("/**", "user"); //user表示配置记住我或认证通过可以访问的地址
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* SpringShiroFilter首先注册到spring容器
* 然后被包装成FilterRegistrationBean
* 最后通过FilterRegistrationBean注册到servlet容器
* @return
*/
@Bean
public FilterRegistrationBean delegatingFilterProxy(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
DelegatingFilterProxy proxy = new DelegatingFilterProxy();
proxy.setTargetFilterLifecycle(true);
proxy.setTargetBeanName("shiroFilter");
filterRegistrationBean.setFilter(proxy);
return filterRegistrationBean;
}
//设置cookie
@Bean
public SimpleCookie rememberMeCookie(){
//这个参数是cookie的名称,对应前端的checkbox的name=rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//记住我cookie生效时间3个小时(单位秒)
simpleCookie.setMaxAge(10800);
return simpleCookie;
}
//cookie管理对象,记住我功能
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
//如果没有这两个配置,可能会授权失败,所以依赖中还需要配置aop的依赖
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
//这里是为了能在html页面引用shiro标签
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
}
4.全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ShiroException.class)
public String doHandleShiroException(ShiroException se, Model model) {
se.printStackTrace();
if(se instanceof UnknownAccountException){ //该账号不存在
return "login";
}
if(se instanceof LockedAccountException){ //该账户已被锁定,请联系管理员
return "login";
}
if(se instanceof IncorrectCredentialsException){//密码错误
return "login";
}
if(se instanceof AuthorizationException){ //没有相应权限,请联系管理员
return "403";
}else{ //登录失败
return "login";
}
}
}
5.LoginController
@Controller
public class LoginController {
@GetMapping("/login")
public String login() {
return "login";
}
@PostMapping("/userLogin")
public String toLogin(String username, String password, Model model){
UsernamePasswordToken token =new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
return "redirect:user/list";
} catch (UnknownAccountException e) {
model.addAttribute("msg","该账号不存在");
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg","密码错误,请重试");
} catch (LockedAccountException e) {
model.addAttribute("msg","该账户已被锁定,请联系管理员");
} catch (Exception e) {
model.addAttribute("msg","登录失败");
}
return "login";
}
}
6.权限验证
@GetMapping("/pageList")
@ResponseBody
@RequiresPermissions("user:view")
public String listPage(){
return "测试数据!";
}
7.实现不同的权限显示的页面效果不同
<div>
<a shiro:hasPermission="user:add" href="/toAddUser">添加客户</a>
<a shiro:hasPermission="user:update" href="javascript:void(0)">修改客户</a>
<a shiro:hasPermission="user:delete" href="javascript:void(0)">删除客户</a>
<a shiro:hasPermission="user:export" href="javascript:void(0)">导出客户</a>
</div>
源码地址: https://gitee.com/ChouHo/learning.git