前面对shiro记性了一些逻辑的操作,和具体的代码片段的操作,现在将我写的一个小的案例,总结一下。总结完明天就上班了。
本案例使用的是spring boot + spring mvc +mybatis
项目的结构
首先对pom文件进行操作
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sgqing</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--用于进行数据连接的-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--spring提供的模板文件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<!--包含spring mvc等web操作-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--shiro包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--用的是mysql的数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>-->
<!--spring boot-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
下面对application.yml进行配置
<!--对数据库进行配置-->
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
<!--对tomcat进行设置启动的端口-->
server:
port: 9992
<!--对mybatis进行设置-->
mybatis:
typeAliasesPackage: com.sgqing.demo.dao
mapperLocations: classpath:mapper/*.xml
下面对shiro的核心两个类进行操作,这两个类分别代表的是认证和授权
package com.sgqing.demo.comfig;
import com.sgqing.demo.entity.SysPermission;
import com.sgqing.demo.entity.SysRole;
import com.sgqing.demo.entity.UserInfo;
import com.sgqing.demo.sevice.UserInfoService;
import org.apache.coyote.http2.ByteUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserInfoService userInfoService;
/**
* 进行授权
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 进行获取用户信息
UserInfo info = (UserInfo) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//对用户和角色进行分别的获取,然后添加到SimpleAuthorizationInfo返回
for (SysRole role : info.getRoleList()) {
// 将角色放到SimpleAuthorizationInfo中
authorizationInfo.addRole(role.getRole());
for (SysPermission permission : role.getPermissions()) {
authorizationInfo.addStringPermission(permission.getPermission());
}
}
return authorizationInfo;
}
/**
* 进行认证
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 首先获取页面传递过来的数据 -- 用户名
String name = (String) authenticationToken.getPrincipal();
System.out.println(authenticationToken.getCredentials());
UserInfo byUsername = userInfoService.findByUsername(name);
System.out.println(" ByteSource.Util.bytes(byUsername.getCredentialsSalt()):" + ByteSource.Util.bytes(byUsername.getCredentialsSalt()));
// ByteSource.Util.bytes(byUsername.getCredentialsSalt()), 对密码进行加密操作,该参数是 盐 md5
SimpleAuthenticationInfo authenticationInfo =
new SimpleAuthenticationInfo(
name,
byUsername.getPassword(),
ByteSource.Util.bytes(byUsername.getCredentialsSalt()),
getName()
);
return authenticationInfo;
}
}
使用类的配置
package com.sgqing.demo.comfig;
import com.sgqing.demo.Except.MyExceptionResolver;
import org.aopalliance.aop.Advice;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Shiro的配置
*/
@Configuration
public class ShiroConfig {
/**
* 该bena是当用户访问某个权限的时候,如果没有指定的权限进行跳转的页面
*
* @return
*/
@Bean
public MyExceptionResolver myExceptionResolver() {
MyExceptionResolver resolver = new MyExceptionResolver();
return resolver;
}
/**
* 因为在密码返回的时候,我们加了盐,所以需要进行解密
* @return
*/
@Bean
public HashedCredentialsMatcher credentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");
hashedCredentialsMatcher.setHashIterations(2);//相当于md5(md5(""))
return hashedCredentialsMatcher;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
// 因为在使用的时候设置了md5进行密码的加密,所以需要进行解密
myShiroRealm.setCredentialsMatcher(credentialsMatcher());
return myShiroRealm;
}
//设置SecurityManager
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager defaultWebSecurityManager =
new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(myShiroRealm());
return defaultWebSecurityManager;
}
//首先设置shiro的工厂类
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 进行拦截器的设置
Map<String, String> filterMap = new HashMap<>();
filterMap.put("/static/**", "anon");
filterMap.put("/logout", "logout");
filterMap.put("/**", "authc");
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
// 开启shiro的注解 开启代理
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
/**
* 异常处理
*
* @return
*/
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("DatabaseException", "databaseError");//数据库异常处理
properties.setProperty("UnauthorizedException", "403");
resolver.setExceptionMappings(properties);
resolver.setDefaultErrorView("error"); // No default
resolver.setExceptionAttribute("ex"); // Default is "exception"
return resolver;
}
}
配置的当没有权限的时候,跳转的页面
package com.sgqing.demo.Except;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 用于设置当没有访问权限的时候,用于跳转指定的页面,用到ModelAndView来进行设置页面的跳转
*/
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
// TODO Auto-generated method stub
System.out.println("==============异常开始=============");
//如果是shiro无权操作,因为shiro 在操作auno等一部分不进行转发至无权限url
if (ex instanceof UnauthorizedException) {
ModelAndView mv = new ModelAndView("/403");
return mv;
}
ex.printStackTrace();
System.out.println("==============异常结束=============");
ModelAndView mv = new ModelAndView("/403");
return mv;
}
}
这是代码中一些重要的代码片段,如果有需要代码的,可以下载我们的案例,在案例中没有提供数据库的检表语句,需要自己手动创建库和表:https://gitee.com/sgqing/spring-boot--springmvc--shiro.git