1、新建shiro-test工程,选择Spring Web和Thymeleaf依赖
2、添加相关依赖包
<!--添加shiro依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--添加shiro支持thymeleaf标签依赖-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--添加shiro EhCache缓存依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
3、在resources下添加ehcache添加ehcache缓存配置文件ehcache.xml
配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<ehcache>
<!-- 磙盘的缓存位置-->
<diskStore path="java.io.tmpdir/ehcache"/>
<!--默认缓存-->
<defaultCache
maxEntriesLocalHeap="10000"
eternal = "false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy ="localTempSwap"/>
</defaultCache>
<!-- ShiroTest缓存 -->
<cache name ="ShiroTestCache"
maxEntriesLocalHeap="1000"
eternal = "false"
timeToIdleSeconds="5"
timeToLiveSeconds="5"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
4、在static下新建js文件夹,并将md5 js加密算法与 jquery复制到js下
5、template下添加login.html,noPermission.html,Index.html
<!--login.html-->
<!DOCTYPE html>
<html lang="en" xmlns:th ="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script th:src="@{|/js/jquery-1.8.0.min.js|}"></script>
<script th:src="@{|/js/jquery.md5.js|}"></script>
<script>
//页面加载完毕后将登录按钮单件事件绑定以下方法
$(function(){
$("#btnSubmit").bind("click",function() {
var md5_password = $.md5($("#password").val());
console.log(md5_password);
alert(md5_password);
$("#md5Password").val(md5_password);
})
})
</script>
</head>
<body>
<form action ="/" method="post">
<label>用户名</label><input type = "text" id = "userName" name ="userName"><br>
<label>密码</label><input type ="password" id = "password"><br>
<input type ="hidden" id = "md5Password" name ="password">
<input type = "submit" id ="btnSubmit" value ="登录">
<span style="color:firebrick" th:text="${errMessage}"/>
</form>
</body>
</html>
<!--noPermission.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 style="color: firebrick">对不起,您没有操作权限</h1>
</body>
</html>
<!--index.html-->
<!DOCTYPE html>
<!--添加thymeleaf与shiro命名空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro ="http://www.polix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<shiro:guest>
您还没有登录
</shiro:guest>
<a th:href = "@{|/user/add|}">添加用户</a>
<a th:href = "@{|/user/update|}">修改用户</a>
<a th:href = "@{|/user/delete|}">删除用户</a>
<!--登录之后才可以查找用户-->
<shiro:authenticated>
<a th:href = "@{|/user/search|}">查找用户</a>
</shiro:authenticated>
</body>
</html>
</body>
</html>
6、添加controller文件夹,并在其下添加TestController类
package com.example.shirotest.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class TestController {
@GetMapping("/index")
public String index (){
return "index";
}
@GetMapping("/")
public String toLogin(){
return "login";
}
@PostMapping("/")
public String login(String userName, String password, Model model){
Subject subject = SecurityUtils.getSubject();
subject.logout();
/*如果用户没有通过认证,认证用户*/
if(!subject.isAuthenticated()){
//创建UsernamePasswordToke对象
String errMessage;
UsernamePasswordToken token = new UsernamePasswordToken(userName,password);
try {
subject.login(token);
} catch (UnknownAccountException e) {
errMessage = "用户名不存在";
model.addAttribute("errMessage",errMessage);
return "login";
} catch (IncorrectCredentialsException e){
errMessage = "密码不正确";
model.addAttribute("errMessage",errMessage);
return "login";
} catch(LockedAccountException e){
model.addAttribute("errMessage","您的账号已经被锁定");
return "login";
}
catch (AuthenticationException e){
model.addAttribute("errMessage","认证失败");
return "login";
}
}
return "redirect:index";
}
@RequiresPermissions(value ={"user:add"})
@RequestMapping("/user/add")
@ResponseBody
public String userAdd(){
return "userAdd";
}
@RequiresPermissions(value={"user:update"})
@RequestMapping("/user/update")
@ResponseBody
public String userUpdate(){
return "userUpdate";
}
@RequiresPermissions(value ={"user:delete"})
@RequestMapping("/user/delete")
@ResponseBody
public String userDelete(){
return "userDelete";
}
@RequestMapping("/user/search")
@ResponseBody
public String userSelect(){
return "userSelect";
}
@RequestMapping("/noPermission")
public String noPermission(){
return "noPermission";
}
//通过@RequiresPermission标识的无权限异常在此处理
@ExceptionHandler(value={AuthorizationException.class})
public String permissionError(Throwable throwable){
return "noPermission";
}
}
7、添加自定义realm MyRealm继承自AuthorizingRealm
package com.example.shirotest.realm;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.HashSet;
import java.util.Set;
public class MyRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Object obj = principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set<String> roles = new HashSet<>();
Set<String> permissions = new HashSet<>();
//此处应该是根据用户名查询出所有角色与权限
if(obj.equals("admin")){
roles.add("admin");
permissions.add("user:add");
permissions.add("user:update");
permissions.add("user:delete");
permissions.add("user:search");
}
info.addRoles(roles);
info.addStringPermissions(permissions);
return info;
}
//认证账户
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//根据principalCollection参数获得authenticationToken
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
String userName = token.getUsername();
String password = new String(token.getPassword());
//此部分应该是查找数据库后根据是否存在用户及用户密码输错次数判断
if(!"admin".equals(userName) && !"zhangsan".equals(userName) && !"user".equals(userName)){
throw new UnknownAccountException();
}else if("zhangsan".equals(userName)){
throw new LockedAccountException();
}
/*
*参数1:服务器或输入的用户名,参数2:服务器中的密码,参数3,当前rea的名字
*/
return new SimpleAuthenticationInfo(userName,"e10adc3949ba59abbe56e057f20f883e",getName());
}
}
8、添加config文件夹,并添加ShiroConfig配置类
package com.example.shirotest.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.example.shirotest.realm.MyRealm;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//生成MyRealm bean
@Bean
public MyRealm myRealm(){
MyRealm myRealm = new MyRealm();
return myRealm;
}
//生成EhCache bean
@Bean
public EhCacheManager ehCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
InputStream inputStream = null;
try {
inputStream = ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache.xml");
} catch (IOException e) {
e.printStackTrace();
}
CacheManager cacheManager = new CacheManager(inputStream);
ehCacheManager.setCacheManager(cacheManager);
return ehCacheManager;
}
//生成SecurityManager bean
@Bean
public SecurityManager securityManager(MyRealm myRealm,EhCacheManager ehCacheManager){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
//securityManager.setCacheManager(ehCacheManager);
return securityManager;
}
//生成ShiroFilterFactoryBean bean
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
//创建ShiroFilterFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置SecurityManager对象
shiroFilterFactoryBean.setSecurityManager(securityManager);
//设置登录页面
shiroFilterFactoryBean.setLoginUrl("/");
//设置登录成功后跳转的页面
shiroFilterFactoryBean.setSuccessUrl("/index");
//设置没有权限跳转的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noPermission");
/*
* 设置页面拦截规则
*/
Map<String,String> filterChainMap = new LinkedHashMap<>();
//配置登陆请求不需要认证 anon表示某个请求不需要认证
filterChainMap.put("/","anon");
filterChainMap.put("/noPermission","anon");
//配置登出的请求,登出后会清空当前用户的内存
filterChainMap.put("/logout","logout");
//配置一个admin开头的所有请求需要登录 authc表示需要登录认证
filterChainMap.put("/user/add","authc,roles[admin]");
//配置一个user开头的所有请求需要登录 authc表示需要登录认证
filterChainMap.put("/user/**","authc");
filterChainMap.put("/js/**","anon");
//配置剩余的所有请求全部需要进行登录认证(注意:这个必须写在最后面,否则其后的配置不管用),可选配置
filterChainMap.put("/**","authc");
//设置权限拦截规则
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
return shiroFilterFactoryBean;
}
//开启shiro注解支持,不开启controller中的@RequiresPermissions无效
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
//开启AOP的支持,不开启controller中的@RequiresPermissions无效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
//配置shiro与thymeleaf的集成
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
}