💗wei_shuo的个人主页
💫wei_shuo的学习社区
🌐Hello World !
Shiro
Shiro是一个安全框架,用于认证、授权和管理应用程序的安全性。它提供了一组易于使用的API和工具,可以帮助您轻松地添加安全性到您的应用程序中;保护应用程序的机密性、完整性和可用性。可以与各种应用程序集成,包括Web应用程序、RESTful服务和基于消息的应用程序等。使用Shiro,您可以轻松地实现身份验证、权限控制、密码加密等功能,以确保您的应用程序得到充分的安全保护;
Security 和 Shiro
Spring Security和Shiro都是用于应用程序安全的框架,它们都提供了认证、授权和安全管理等方面的功能,但它们在实现方式和设计哲学上有一些不同。
- 来源不同:Spring Security最初是Spring框架的一个子项目,而Shiro是从Apache的一个开源项目而来
- 架构不同:Spring Security的设计哲学是将安全性集成到应用程序的架构中,这意味着Spring Security在许多方面都与Spring框架紧密耦合。而Shiro的设计哲学是通过简单的API和注解来实现安全性,使它可以与各种框架和技术集成
- 功能不同:尽管Spring Security和Shiro都提供了基本的认证和授权功能,但它们的实现方式和可定制性略有不同。Spring Security具有更多的配置选项和扩展性,而Shiro则更加简单易用,但可能在某些方面缺少灵活性
- 社区支持不同:由于Spring Security是Spring框架的一部分,因此它拥有强大的社区支持和生态系统。而Shiro虽然也有不错的社区支持,但在某些方面可能不如Spring Security流行
综上所述,选择Spring Security还是Shiro取决于您的具体需求和技术偏好。如果您已经使用了Spring框架,那么Spring Security可能是更好的选择。如果您需要一个更加简单易用的框架,并且需要与各种技术集成,那么Shiro可能更适合您的需求
Authentication:保证只有具有权限的用户才能访问系统中的特定资源,比如用户名/密码、敏感资源等。这样可以保护系统的安全性,防止未经授权的用户访问重要信息;
Authorization:作用在于根据用户提供的身份凭证,生成权限实体,并为之授予相应的权限;
Session Management:会话管理,Session 管理的作用主要是在网站浏览时保存用户的会话状态,当用户关闭浏览器时自动关闭会话,从而避免数据泄露;
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web 支持,可以非常容易的集成到 Web 环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率;
Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
Testing:提供测试支持;
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
Remember Me:记住我,通过session缓存数据
Subject(主体) :Shiro 框架中的一个核心概念获取当前登录的用户名和角色,验证当前用户的权限,提供当前用户信息,包括用户名、角色、权限等信息
SecurityManager(核心安全管理器): 是一个安全管理器,主要对账号、权限及身份认证进行设置和管理。它可以对 Spark 的部署模式进行配置,开放指定的权限,没有配置的权限就认为不具备相应的权限,这个安全管理器默认情况下是关闭的,需要手动去开启
Realm(领域) : Shiro 框架中用于保护应用程序中的数据安全的一种数据库;当用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息。Realm 实质上是一个安全相关的 DAO,它封装了数据源的连接细节,并在需要时将相关数据提供给 Shiro。当配置 Shiro 时,你必须至少指定一个 Realm,用于认证和(或)授权。配置多个 Realm 是可以的,但是至少需要一个。Shiro 内置了可以连接大量安全数据源(又名目录)的 Realm,如 LDAP、关系数据库(JDBC)、类似 INI 的文本配置资源以及属性文件等。如果缺省的 Realm 不能满足需求,你还可以插入代表自定义数据源的自己的 Realm 实现。Realm 能做的工作主要有以下几个方面:
- 身份验证:验证账户和密码,并返回相关信息
- 权限获取:获取指定身份的权限,并返回相关信息
- 令牌支持:判断该令牌(Token)是否被支持
- 令牌有很多种类型,例如:HostAuthenticationToken(主机验证令牌),UsernamePasswordToken(账户密码验证令牌)
准备工作
- 依赖导入
<dependencies><!--shiro-core--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.11.0</version></dependency><!--configure logging--><!--jcl-over-slf4j--><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>2.0.7</version></dependency><!--slf4j-log4j12--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>2.0.7</version></dependency><!--log4j--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies>
- resources/log4j.properties
log4j.rootLogger=INFO, stdoutlog4j.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
- resources/shiro.ini
[users] # user 'root' with password 'secret' and the 'admin' role root = secret, admin # user 'guest' with the password 'guest' and the 'guest' role guest = guest, guest # user 'presidentskroob' with password '12345' ("That's the same combination on # my luggage!!!" ;)), and role 'president' presidentskroob = 12345, president # user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz' darkhelmet = ludicrousspeed, darklord, schwartz # user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz' lonestarr = vespa, goodguy, schwartz[roles] # 'admin' role has all permissions, indicated by the wildcard '*' admin = * # The 'schwartz' role can do anything (*) with any lightsaber: schwartz = lightsaber:* # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with # license plate 'eagle5' (instance specific id) goodguy = winnebago:drive:eagle5
- Quickstart.java
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;/*** Simple Quickstart application showing how to use Shiro's API.** @since 0.9 RC2*/ 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);} }
shiro的subject分析
- 获取当前用户对象subject
Subject currentUser = SecurityUtils.getSubject();
- 通过当前用户,取出session
Session session = currentUser.getSession();
- 判断当前用户是否被认证
if (!currentUser.isAuthenticated()) {…… }
- 输出Subject信息,或得当前用户认证
log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
- 获取用户是否拥有角色,并输出
if (currentUser.hasRole("schwartz")) {…… }
- 获取当前用户权限
if (currentUser.isPermitted("lightsaber:wield")) {…… }
- 注销、结束
//注销currentUser.logout();//结束System.exit(0);
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) {Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//获取当前用户对象Subject currentUser = SecurityUtils.getSubject();//通过当前用户,取出sessionSession session = currentUser.getSession();session.setAttribute("someKey", "aValue");String value = (String) session.getAttribute("someKey");if (value.equals("aValue")) {log.info("Retrieved the correct value! [" + value + "]");}//判断当前用户是否被认证if (!currentUser.isAuthenticated()) {UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");//token:令牌token.setRememberMe(true);try {//执行登录操作currentUser.login(token);//Subject异常} 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 (AuthenticationException ae) {}}//输出Subject信息,或得当前用户认证log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");//测试角色,如果角色拥有权限,则输出权限信息if (currentUser.hasRole("schwartz")) {log.info("May the Schwartz be with you!");} else {log.info("Hello, mere mortal.");}//粗粒度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.");}//细粒度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!");}//注销currentUser.logout();//结束System.exit(0);} }
springboot集成shiro
- 依赖导入
<dependencies><!--shiro-springboot--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.11.0</version></dependency><!--thymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
- Shiro 框架的配置文件(ShiroConfig)
package com.wei.config;import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import java.util.LinkedHashMap; import java.util.Map;@Configuration public class ShiroConfig {//ShiroFilterFactoryBean@Bean(name = "shiroFilterFactoryBean")public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();//设置安全管理器bean.setSecurityManager(defaultWebSecurityManager);//添加shiro的内置过滤器/*** anon:无需认证,即可访问* authc:必须认证,才能访问* user:必须拥有rember me 功能才能使用* perms:必须对某个资源的权限才能访问* role:拥有某个角色权限才能访问* *///登录拦截器Map<String, String> filterMap = new LinkedHashMap<>();//filterMap.put("/user/*","authc");filterMap.put("/user/add","authc");filterMap.put("/user/update","authc");bean.setFilterChainDefinitionMap(filterMap);//设置登录请求bean.setLoginUrl("/toLogin");return bean;}//DefaultWebSecurityManager@Bean(name = "securityManager")public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();//关联UserRealmsecurityManager.setRealm(userRealm);return securityManager;}//Realm对象@Beanpublic UserRealm userRealm(){return new UserRealm();} }
- login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><h1>登录</h1><p th:text="${msg}" style="color: red"></p><form th:action="@{/login}"><p>用户名:<input type="text" name="username"></p><p>密码:<input type="text" name="password"></p><p><input type="submit"></p> </form></body> </html>
- index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>wei_shuo</title> </head> <body> <div><span><h1>首页</h1></span><p th:text="${msg}"></p><hr><a th:href="@{/user/add}"><h1>add</h1></a> <a th:href="@{/user/update}"><h1>update</h1></a> </div> </body> </html>
- add.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h1>add User</h1> </body> </html>
- update.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h1>update User</h1> </body> </html>
- MyController.java
package com.wei.controller;import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping;@Controller public class MyController {@RequestMapping({"/", "index"})public String toIndex(Model model) {model.addAttribute("msg", "Hello,Shiro");return "index";}@RequestMapping("/user/add")public String add() {return "user/add.html";}@RequestMapping("/user/update")public String update() {return "user/update.html";}@RequestMapping("/toLogin")public String toLogin() {return "login";}@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 e) { //用户名不存在model.addAttribute("msg", "用户名错误");return "login";} catch (IncorrectCredentialsException e) { //密码不存在model.addAttribute("msg", "密码错误");return "login";}} }
- UserRealm.java(用户认证与授权)
package com.wei.config;import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject;//自定义UserRealm public class UserRealm extends AuthorizingRealm {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了=>授权doGetAuthorizationInfo");return null;}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("执行了=>认证doGetAuthorizationInfo");//用户名,密码,数据库String name = "root";String password = "123456";UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;//用户认证if (!userToken.getUsername().equals(name)){return null; //抛出异常 UnknownAccountException}//密码认证,shiro自动部署return new SimpleAuthenticationInfo("",password,"");} }
shiro集成Mybatis
- 依赖导入
<dependencies><!--springboot-mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.0</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--log4j--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!--druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.16</version></dependency><!--shiro-springboot--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.11.0</version></dependency><!--thymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
- 配置文件application.properties
#整合mybatis mybatis.type-aliases-package=com.wei.pojo mybatis.mapper-locations=classpath:mapper/*.xml
- 数据库配置application.yml
spring:datasource:username: "root"password: "root"url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTCdriver-class-name: com.mysql.cj.jdbc.Driver#切换数据源type: com.alibaba.druid.pool.DruidDataSource#Spring Boot 默认是不注入这些属性值的,需要自己绑定#druid 数据源专有配置initialSize: 5minIdle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4jfilters: stat,wall,log4jmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
- /pojo/User.java
package com.wei.pojo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;@Data @AllArgsConstructor @NoArgsConstructor public class User {private int id;private String name;private String pwd; }
- /mapper/UserMapper.java
package com.wei.mapper;import com.wei.pojo.User; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository;@Repository @Mapper public interface UserMapper {public User queryUserByName(String name); }
- /resource/mapper/UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wei.mapper.UserMapper"><select id="queryUserByName" parameterType="String" resultType="User">select * from mybatis.user where name = #{name}</select></mapper>
- /service/UserService.java
package com.wei.service;import com.wei.pojo.User;public interface UserService {public User queryUserByName(String name); }
- /service/UserServiceImpl.java
package com.wei;import com.wei.service.UserServiceImpl; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest class Springboot06ShiroApplicationTests {@AutowiredUserServiceImpl userService;@Testvoid contextLoads() {System.out.println(userService.queryUserByName("aaa"));}}
- 测试
package com.wei;import com.wei.service.UserServiceImpl; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest class Springboot06ShiroApplicationTests {@AutowiredUserServiceImpl userService;@Testvoid contextLoads() {System.out.println(userService.queryUserByName("aaa"));}}
- /config/UserRealm.java
package com.wei.config;import com.wei.pojo.User; import com.wei.service.UserService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired;//自定义UserRealm public class UserRealm extends AuthorizingRealm {@AutowiredUserService userService;//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了=>授权doGetAuthorizationInfo");return null;}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("执行了=>认证doGetAuthorizationInfo");UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;//连接数据库User user = userService.queryUserByName(userToken.getUsername());if (user==null){return null; //UnknownAccountException}//密码认证,shiro自动部署//密码加密return new SimpleAuthenticationInfo("",user.getPwd(),"");} }
用户认证与授权
- 数据库配置
- config/ShiroConfig.java
package com.wei.config;import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import java.util.LinkedHashMap; import java.util.Map;@Configuration public class ShiroConfig {//ShiroFilterFactoryBean@Bean("shiroFilterFactoryBean")public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();//设置安全管理器bean.setSecurityManager(defaultWebSecurityManager);//添加shiro的内置过滤器/*** anon:无需认证,即可访问* authc:必须认证,才能访问* user:必须拥有rember me 功能才能使用* perms:必须对某个资源的权限才能访问* role:拥有某个角色权限才能访问* *///登录拦截器Map<String, String> filterMap = new LinkedHashMap<>();//filterMap.put("/user/*","authc");filterMap.put("/user/add","authc");filterMap.put("/user/update","authc");bean.setFilterChainDefinitionMap(filterMap);//授权filterMap.put("/user/add","perms[user:add]");filterMap.put("/user/update","perms[user:update]");//设置登录请求bean.setLoginUrl("/toLogin");//设置未授权的请求bean.setUnauthorizedUrl("/noauth");return bean;}//DefaultWebSecurityManager@Bean("SecurityManager")public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();//关联UserRealmsecurityManager.setRealm(userRealm);return securityManager;}//Realm对象@Beanpublic UserRealm userRealm(){return new UserRealm();} }
config/UserRealm.java
package com.wei.config;import com.wei.pojo.User; import com.wei.service.UserService; import org.apache.shiro.SecurityUtils; 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 org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired;//自定义UserRealm public class UserRealm extends AuthorizingRealm {@AutowiredUserService userService;//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了=>授权doGetAuthorizationInfo");//SimpleAuthorizationInfoSimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // info.addStringPermission("user:add"); // info.addStringPermission("user:update");//获取当前用户对象Subject subject = SecurityUtils.getSubject();//获取到了user对象User currentUser = (User) subject.getPrincipal();//设置当前用户权限info.addStringPermission(currentUser.getPerms());return info;}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("执行了=>认证doGetAuthorizationInfo");UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;//连接数据库User user = userService.queryUserByName(userToken.getUsername());if (user==null){return null; //UnknownAccountException}//密码认证,shiro自动部署//密码加密return new SimpleAuthenticationInfo(user,user.getPwd(),"");} }
- controller/MyController.java
package com.wei.controller;import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;@Controller public class MyController {@RequestMapping({"/", "index"})public String toIndex(Model model) {model.addAttribute("msg", "Hello,Shiro");return "index";}@RequestMapping("/user/add")public String add() {return "user/add.html";}@RequestMapping("/user/update")public String update() {return "user/update.html";}@RequestMapping("/toLogin")public String toLogin() {return "login";}@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 e) { //用户名不存在model.addAttribute("msg", "用户名错误");return "login";} catch (IncorrectCredentialsException e) { //密码不存在model.addAttribute("msg", "密码错误");return "login";}}//未授权页面@RequestMapping("/noauth")@ResponseBodypublic String unauthorized(){return "未经授权无法访问此页面!";} }
shiro继承Thymeleaf
- 依赖导入
<!--shiro-thymeleaf--><dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>2.1.0</version></dependency>
- config/ShiroConifg.java
//整合ShiroDialect:整合shiro和thymeleaf@Beanpublic ShiroDialect getShiroDialect(){return new ShiroDialect();}
- config/UserRealm.java
//获取当前的用户Subject currentSubject = SecurityUtils.getSubject();Session session = currentSubject.getSession();session.setAttribute("loginUser",user);
- index.html
<!DOCTYPE html> <html lang="en"xmlns:th="http://www.thymeleaf.org"xmlns:shiro="http://www.pollix.at/thymeleaf/shiro" > <head><meta charset="UTF-8"><title>wei_shuo</title> </head> <body> <div><span><h1>首页</h1></span><div th:if="${session.loginUser==null}"><p><a th:href="@{/toLogin}">登录</a> </p></div><p th:text="${msg}"></p><hr><div shiro:hasPermission="'user:add'"><a th:href="@{/user/add}"><h1>add</h1></a></div><div shiro:hasPermission="'user:update'"><a th:href="@{/user/update}"><h1>update</h1></a></div> </div> </body> </html>
🌼 结语:创作不易,如果觉得博主的文章赏心悦目,还请——
点赞
👍收藏
⭐️评论
📝