能够先建立一个最单纯的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