能夠先建立一個最單純的Maven項目。html
<dependencies> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>2.0.0-alpha1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>2.0.0-alpha1</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
這裏我導入的依賴基本上都是最新版,若是想要別的版本能夠自行搜索導入java
log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n # General Apache libraries log4j.logger.org.apache=WARN # Spring log4j.logger.org.springframework=WARN # Default Shiro logging log4j.logger.org.apache.shiro=INFO # Disable verbose logging log4j.logger.org.apache.shiro.util.ThreadContext=WARN log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
這裏第一次建立ini文件,會讓你選擇,能夠選擇txt文件,建立成功後會提示你創下載一個ini插件:mysql
[users] root = secret, admin guest = guest, guest presidentskroob = 12345, president darkhelmet = ludicrousspeed, darklord, schwartz lonestarr = vespa, goodguy, schwartz [roles] admin = * schwartz = lightsaber:* goodguy = winnebago:drive:eagle5
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Quickstart { private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class); public static void main(String[] args) { // The easiest way to create a Shiro SecurityManager with configured // realms, users, roles and permissions is to use the simple INI config. // We'll do that by using a factory that can ingest a .ini file and // return a SecurityManager instance: // Use the shiro.ini file at the root of the classpath // (file: and url: prefixes load from files and urls respectively): Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); // for this simple example quickstart, make the SecurityManager // accessible as a JVM singleton. Most applications wouldn't do this // and instead rely on their container configuration or web.xml for // webapps. That is outside the scope of this simple quickstart, so // we'll just do the bare minimum so you can continue to get a feel // for things. SecurityUtils.setSecurityManager(securityManager); // Now that a simple Shiro environment is set up, let's see what you can do: // get the currently executing user: Subject currentUser = SecurityUtils.getSubject(); // Do some stuff with a Session (no need for a web or EJB container!!!) Session session = currentUser.getSession(); session.setAttribute("someKey", "aValue"); String value = (String) session.getAttribute("someKey"); if (value.equals("aValue")) { log.info("Retrieved the correct value! [" + value + "]"); } // let's login the current user so we can check against roles and permissions: if (!currentUser.isAuthenticated()) { UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); token.setRememberMe(true); try { currentUser.login(token); } catch (UnknownAccountException uae) { log.info("There is no user with username of " + token.getPrincipal()); } catch (IncorrectCredentialsException ice) { log.info("Password for account " + token.getPrincipal() + " was incorrect!"); } catch (LockedAccountException lae) { log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } // ... catch more exceptions here (maybe custom ones specific to your application? catch (AuthenticationException ae) { //unexpected condition? error? } } //say who they are: //print their identifying principal (in this case, a username): log.info("User [" + currentUser.getPrincipal() + "] logged in successfully."); //test a role: if (currentUser.hasRole("schwartz")) { log.info("May the Schwartz be with you!"); } else { log.info("Hello, mere mortal."); } //test a typed permission (not instance-level) if (currentUser.isPermitted("lightsaber:wield")) { log.info("You may use a lightsaber ring. Use it wisely."); } else { log.info("Sorry, lightsaber rings are for schwartz masters only."); } //a (very powerful) Instance Level permission: if (currentUser.isPermitted("winnebago:drive:eagle5")) { log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " + "Here are the keys - have fun!"); } else { log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!"); } //all done - log out! currentUser.logout(); System.exit(0); } }
解決辦法:git
這是由於你的依賴中的問題:github
<dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>2.0.0-alpha1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>2.0.0-alpha1</version> <scope>test</scope> </dependency>
依賴中存在
對於shiro環境,一共有三個要素:spring
咱們須要倒着來建立sql
建立一個config文件夾,和ShiroConfig、UserRealm類數據庫
public class UserRealm extends AuthorizingRealm { // 受權 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } //認證 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { return null; } }
@Configuration public class ShiroConfig { //ShiroFilterFactoryBean @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //設置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); return bean; } //DefaultWebSecurityManager @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager SecurityManager = new DefaultWebSecurityManager(); SecurityManager.setRealm(userRealm); return SecurityManager; } //建立 realm 對象 @Bean public UserRealm userRealm(){ return new UserRealm(); } }
以上就完成了shiro的基本框架搭建。apache
用來測試的話,咱們須要:
add.html、index.html、login.html和一個Controller類
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> add </body> </html>
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 首頁<br> <a th:href="@{/add}">add</a><br> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action=""> 姓名:<input type="text" name="username"><br> 密碼:<input type="text" name="password"><br> <input type="submit" value="提交"> </form> </body> </html>
@Controller public class ShiroController { @RequestMapping({"/","/index.html"}) public String index(){ return "index"; } @RequestMapping("/add") public String add(){ return "add"; } @RequestMapping("/toLogin") public String login(){ return "login"; } }
上述文件頁面搭建好後,測試運行應該是沒什麼問題的,咱們開始在ShiroConfig類中配置
@Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //設置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); //添加shiro的內置過濾器 /* * anon:無需認證就能夠訪問 * authc:必須認證了才能訪問 * user:必須擁有 記住我 功能才能用 * perms:擁有對某個資源的權限才能訪問 * role:擁有某個角色權限才能訪問 */ Map<String, String> map = new LinkedHashMap<>(); map.put("/add","authc"); map.put("/update","authc"); bean.setFilterChainDefinitionMap(map); //設置登陸請求 bean.setLoginUrl("/toLogin"); return bean; }
這時候,若是沒有權限,點擊add會自動進入設置的登錄頁面。
添加登陸Controller
@RequestMapping("/Login") public String login(String username, String password, Model model){ //獲取當前用戶 Subject subject = SecurityUtils.getSubject(); //封裝用戶的登錄數據 UsernamePasswordToken token = new UsernamePasswordToken(username,password); try { subject.login(token); return "index"; } catch (UnknownAccountException uae) { model.addAttribute("msg","用戶名錯誤"); return "login"; } catch (IncorrectCredentialsException ice) { model.addAttribute("msg","密碼錯誤"); return "login"; } }
修改UserRealm
//認證 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //用戶名密碼 先用下面的測試,以後能夠鏈接數據庫 String name="root"; String password="123456"; UsernamePasswordToken Token = (UsernamePasswordToken) authenticationToken; if (!Token.getUsername().equals(name)){ return null; //自動拋出異常 } //密碼認證 shiro來作 return new SimpleAuthenticationInfo("",password,""); }
修改登陸頁面
<p th:text="${msg}"></p> <form th:action="@{/Login}"> 姓名:<input type="text" name="username"><br> 密碼:<input type="text" name="password"><br> <input type="submit" value="提交"> </form>
以後就能夠去測試了。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency>
application.yml:
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 148729 url: jdbc:mysql://localhost:3306/mybatistest?serverTime=UTC&useUnicode=true&characterEncoding=utf-8 #druid配置 #配置初始化大小/最小/最大 initialSize: 5 minIdle: 5 maxActive: 20 #獲取鏈接等待超時時間 maxWait: 60000 #間隔多久進行一次檢測,檢測須要關閉的空閒鏈接 timeBetweenEvictionRunsMillis: 60000 #一個鏈接在池中最小生存的時間 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false #打開PSCache,並指定每一個鏈接上PSCache的大小。oracle設爲true,mysql設爲false。分庫分表較多推薦設置爲false poolPreparedStatements: false maxPoolPreparedStatementPerConnectionSize: 20 #監控統計攔截的filters,stat:監控統計;log4j:日誌記錄;wall:防護sql注入;若是啓用log4j記得添加依賴 filters: stat,wall,log4j useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
application.properties:
mybatis.type-aliases-package=com.zc.pojo mybatis.mapper-locations=classpath:mapper/*.xml
public class User { private Integer id; private String name; private String pwd; // Get/Set方法 // toString()方法 // 有參/無參方法 }
建立一個mapper文件夾,UserMapper:
@Mapper @Repository public interface UserMapper { User queryUserByName(String name); }
這個文件的位置按照以前配置:
在resources/mapper下
mybatis.mapper-locations=classpath:mapper/*.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zc.mapper.UserMapper"> <select id="queryUserByName" resultType="User"> select * from user where name=#{name}; </select> </mapper>
//認證 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken Token = (UsernamePasswordToken) authenticationToken; //用戶名密碼 User user = userMapper.queryUserByName(Token.getUsername()); String name=user.getName(); String password=user.getPwd(); if (user==null){ return null; } //密碼認證 shiro來作 return new SimpleAuthenticationInfo("",password,""); }
就能夠進行測試了。
建立一個未經受權沒法訪問Controlle方法:
@RequestMapping("/noauth") @ResponseBody public String unauthorized(){ return "未經受權沒法訪問此頁面"; }
修改ShiroConfig:
@Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //設置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); Map<String, String> map = new LinkedHashMap<>(); //攔截 map.put("/add","authc"); map.put("/update","authc"); //受權 map.put("/add","perms[user:add]"); bean.setFilterChainDefinitionMap(map); //設置登陸請求 bean.setLoginUrl("/toLogin"); //攔截頁面 bean.setUnauthorizedUrl("/noauth"); return bean; }
測試
這個時候我已經給/add方法添加了user:add權限,只有有這個權限的用戶才能夠登陸
這時候測試的話,會發現,即時登陸成功經過了攔截,add頁面也會顯示未經受權沒法訪問此頁面
在UserRealm中受權
// 受權 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission("user:add"); return info; }
如今,只要登錄的用戶,都會被添加user:add權限。
也能夠進行數據庫鏈接:
// 受權 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 數據庫中加入一個權限字段,能夠這樣查找 Subject subject = SecurityUtils.getSubject(); //認證部分傳入,能夠獲取 User principal = (User) subject.getPrincipal(); info.addStringPermission(user.getxxx()); return info; } //認證 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken Token = (UsernamePasswordToken) authenticationToken; //用戶名密碼 User user = userMapper.queryUserByName(Token.getUsername()); String password=user.getPwd(); if (user==null){ return null; } //這裏修改了,傳入了user,在受權部分能夠獲取 return new SimpleAuthenticationInfo(user,password,""); }
<dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
導入頭文件
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" >
內部文件
<body> 首頁<br> <a th:href="@{/toLogin}">登陸</a><br> <div shiro:hasPermission="user:add"> <a th:href="@{/add}">add</a><br> </div> <a th:href="@{/update}">update</a> </body>
這種,是最簡單的頁面整理,不一樣權限會顯示不一樣頁面,沒有權限部分功能不展現。
我的博客爲:
MoYu's HomePage
MoYu's Gitee Blog