整合Shiro
4.1 项目准备
创建一个SpringBoot项目整合MyBatis,Thymeleaf,SpringMVC等并创建相关的配置文件和Service逻辑
代码语言:javascript复制 <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.8</version>
</dependency>
<!--devtools 热部署的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
属性配置文件
代码语言:javascript复制server.port=8082
# 配置JDBC的相关信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/logistics?characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
# 配置连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 配置MyBatis的package 设置别名
mybatis.type-aliases-package=com.bobo.pojo
# 指定映射文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml
通过MyBatis Generator自动生成持久层的相关的代码(t_user表)或者从之前的货运系统中拷贝对应的代码
Service的逻辑实现
代码语言:javascript复制package com.bobo.service;
import com.bobo.pojo.User;
import java.util.List;
public interface IUserService {
public User login(String userName);
public List<User> query(User user);
}
代码语言:javascript复制package com.bobo.service.impl;
import com.bobo.mapper.UserMapper;
import com.bobo.pojo.User;
import com.bobo.pojo.UserExample;
import com.bobo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper mapper;
@Override
public User login(String userName) {
User user = new User();
user.setUserName(userName);
List<User> list = this.query(user);
if(list != null && list.size() == 1){
return list.get(0);
}
return null;
}
@Override
public List<User> query(User user) {
UserExample example = new UserExample();
UserExample.Criteria criteria = example.createCriteria();
if(user != null){
if(!"".equals(user.getUserName()) && user.getUserName() != null){
criteria.andUserNameEqualTo(user.getUserName());
}
}
return mapper.selectByExample(example);
}
}
到此准备完成
4.2 Shiro整合
4.2.1 Shiro的依赖
代码语言:javascript复制<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
4.2.2 自定义Realm
代码语言:javascript复制package com.bobo.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class MyRealm extends AuthorizingRealm {
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
4.2.3 Shiro的配置
代码语言:javascript复制package com.bobo.config;
import com.bobo.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.realm.Realm;
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.apache.shiro.mgt.SecurityManager;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
* 配置凭证匹配器
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");
matcher.setHashIterations(1024);
return matcher;
}
/**
* 注册自定义的Realm
* @param hashedCredentialsMatcher
* @return
*/
@Bean
public MyRealm myRealm(CredentialsMatcher hashedCredentialsMatcher){
MyRealm realm = new MyRealm();
realm.setCredentialsMatcher(hashedCredentialsMatcher);
return realm;
}
/**
* 注册SecurityManager对象
* @return
*/
@Bean
public SecurityManager securityManager(Realm myRealm){
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(myRealm);
return manager;
}
/**
* 注册ShiroFilterFactoryBean
* @return
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
filter.setSecurityManager(manager);
filter.setLoginUrl("/login.do");
filter.setSuccessUrl("/success.html");
filter.setUnauthorizedUrl("/refuse.html");
// 设置过滤器
Map<String,String> map = new HashMap<>();
map.put("/css/**","anon");
map.put("/img/**","anon");
map.put("/js/**","anon");
map.put("/login","anon");
map.put("/login.do","authc");
map.put("/**","authc");
filter.setFilterChainDefinitionMap(map);
return filter;
}
}
4.2.4 测试
添加对应的测试文件
代码语言:javascript复制package com.bobo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
@RequestMapping("/login")
public String goLoginPage(){
return "login";
}
}
代码语言:javascript复制package com.bobo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/query")
public String query(){
System.out.println("----user query----");
return "user";
}
}
4.3 认证实现
4.3.1 自定义Realm
在自定义Realm中完成认证逻辑
代码语言:javascript复制package com.bobo.realm;
import com.bobo.pojo.User;
import com.bobo.service.IUserService;
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.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;
public class MyRealm extends AuthorizingRealm {
@Autowired
private IUserService service;
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String userName = token.getUsername();
User user = new User();
user.setUserName(userName);
// 账号验证
user = service.login(userName);
if(user == null){
return null;
}
return new SimpleAuthenticationInfo(user,user.getPassword(),new SimpleByteSource(user.getU1()) ,"myRealm");
}
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
4.3.2 控制器
在控制器中完成认证失败的处理
代码语言:javascript复制package com.bobo.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class LoginController {
@RequestMapping("/login")
public String goLoginPage(){
return "login";
}
@RequestMapping("/login.do")
public String login(HttpServletRequest request){
Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
System.out.println("认证错误的信息:" obj);
return "/login";
}
@RequestMapping("/logout")
public String logout(){
SecurityUtils.getSubject().logout();
return "/login";
}
}
4.3.3 登录页面
代码语言:javascript复制<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录页面</h1>
<form th:action="@{/login.do}" method="post">
账号:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
5. 授权操作
5.1 注解的使用
我们需要开启SpringMVC对注解的支持
代码语言:javascript复制 /**
* 开启对Shiro授权注解的支持
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
在自定义Realm中添加权限
代码语言:javascript复制 /**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User) principalCollection.getPrimaryPrincipal();
System.out.println("获取授权的账号:" user.getUserName());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole("role1");
return info;
}
代码语言:javascript复制<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
启动访问
5.2 标签的使用
添加相关的依赖
代码语言:javascript复制<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
注入对象
代码语言:javascript复制 @Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
在页面中实现处理
代码语言:javascript复制<!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>Title</title>
</head>
<body>
<h1>用户管理</h1>
<shiro:authenticated>
已登录:<shiro:principal property="userName"></shiro:principal>
</shiro:authenticated>
<a href="#" shiro:hasRole="role1">用户查询</a>
<a href="#" shiro:hasRole="role1">用户添加</a>
<a href="#" shiro:hasRole="role2">用户修改</a>
<a href="#" shiro:hasRole="role2">用户删除</a>
</body>
</html>
访问效果