Всем привет, в этой главе мы добавляем функцию интерфейса защиты разрешений shiro. Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь со мной по адресу mr_beany@163.com. Также попросите руководства великих богов, спасибо
Один: что такое сиро
Shiro — это платформа разрешений с открытым исходным кодом для платформы Java для аутентификации и авторизации доступа. В частности, обеспечивается поддержка следующих элементов:
- Пользователи, роли, разрешения (только разрешения на операции, разрешения на данные должны быть тесно связаны с потребностями бизнеса), ресурсы (url).
- Пользователям назначаются роли, а роли определяют разрешения.
- Авторизация доступа поддерживает роли или разрешения, а также поддерживает многоуровневые определения разрешений.
Короче говоря, shiro использует свою собственную конфигурацию, чтобы обеспечить доступ к интерфейсу только с указанными ролями или разрешениями, что обеспечивает безопасность интерфейса.
Два: добавить зависимости shiro
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0-RC2</version>
</dependency>
Третье: создайте таблицы базы данных, такие как разрешения, роли, таблицы отношений разрешений ролей пользователей и т. д.
1: изменить оригиналuserInfo
поверхность
Добавить кpassword(用户密码,经过加密之后的),salt(加密盐值)
После модификации структура выглядит следующим образом
вpassword
Данные генерируются после шифрования 123456
2: Добавить таблицу ролей
CREATE TABLE `sys_role` (
`id` varchar(36) NOT NULL COMMENT '角色名称',
`role_name` varchar(255) DEFAULT NULL COMMENT '角色名称,用于显示',
`role_desc` varchar(255) DEFAULT NULL COMMENT '角色描述',
`role_value` varchar(255) DEFAULT NULL COMMENT '角色值,用于权限判断',
`create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`is_disable` int(1) DEFAULT NULL COMMENT '是否禁用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';
3: Добавить таблицу взаимосвязей ролей пользователей
CREATE TABLE `user_role` (
`id` varchar(36) NOT NULL,
`user_id` varchar(36) DEFAULT NULL COMMENT '用户ID',
`role_id` varchar(36) DEFAULT NULL COMMENT '角色id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色关系表';
4: Добавить таблицу разрешений
CREATE TABLE `sys_perm` (
`id` varchar(36) NOT NULL,
`perm_name` varchar(255) DEFAULT NULL COMMENT '权限名称',
`perm_desc` varchar(255) DEFAULT NULL COMMENT '权限描述',
`perm_value` varchar(255) DEFAULT NULL COMMENT '权限值',
`create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`is_disable` int(1) DEFAULT NULL COMMENT '是否禁用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5: Добавить таблицу разрешений роли
CREATE TABLE `role_perm` (
`id` varchar(36) NOT NULL,
`perm_id` varchar(32) DEFAULT NULL COMMENT '权限id',
`role_id` varchar(32) DEFAULT NULL COMMENT '角色id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色权限表';
Отношения между таблицами примерно следующие: один пользователь соответствует нескольким ролям, а одна роль использует несколько разрешений.
Простите мой острый куриный рисунок
Четвертое: используйте генератор кода для создания картографа, дао, сервиса и контроллера для четырех новых таблиц.
Вы можете сгенерировать его напрямую. Из-за слишком большого количества кода он не будет отображаться здесь. Для получения подробной информации вы можете перейти кОблако кодассылка выше
Пятое: метод добавления ролей запросов и разрешений
UserRoleMapper.xml
<!--根据用户id查询该用户所有角色-->
<select id="getRolesByUserId" resultType="string" parameterType="string">
select sr.role_value
from user_role ur
left join sys_role sr on ur.role_id = sr.id
where ur.user_id = #{userId,jdbcType=VARCHAR}
and sr.is_disable = 0
</select>
UserRoleMapper.java
List<String> getRolesByUserId(String userId);
RolePermMapper.xml
<select id="getPermsByUserId" resultType="string" parameterType="string">
select distinct
p.perm_value
from
sys_perm p,
role_perm rp,
user_role ur
where
p.id = rp.perm_id
and ur.role_id = rp.role_id
and ur.user_id = #{userId,jdbcType=VARCHAR}
and p.is_disable = 0
</select>
Пояснение, здесь запрашиваются все разрешения, соответствующие пользователю.Поскольку роли и разрешения находятся в отношениях «многие ко многим», разрешения запрашиваемого пользователя могут дублироваться.distinct
Иди потяжелее.
RolePermMapper.java
List<String> getPermsByUserId(String userId);
Измените класс сущности userInfo следующим образом.
package com.example.demo.model;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Transient;
import java.util.HashSet;
import java.util.Set;
/**
* @author 张瑶
* @Description:
* @time 2018/4/18 11:55
*/
public class UserInfo {
/**
* 主键
*/
@Id
private String id;
/**
* 用户名
*/
@Column(name = "user_name")
private String userName;
private String password;
/**
* 加密盐值
*/
private String salt;
/**
* 用户所有角色值,用于shiro做角色权限的判断
*/
@Transient
private Set<String> roles;
/**
* 用户所有权限值,用于shiro做资源权限的判断
*/
@Transient
private Set<String> perms;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Set<String> getRoles() {
return roles;
}
public void setRoles(Set<String> roles) {
this.roles = roles;
}
public Set<String> getPerms() {
return perms;
}
public void setPerms(Set<String> perms) {
this.perms = perms;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
}
Шесть: Пользовательский мир
Создать ядро→широ→CustomRealm.java
1: Реализация аутентификации при входе
В Широ информация о пользователе, роли и разрешениях в приложении окончательно получается через Realm. Обычно в Realm информация для аутентификации, которая нужна Широ, получается непосредственно из нашего источника данных. Можно сказать, что Realm — это DAO, посвященная системам безопасности.
Процесс аутентификации Широ в конечном итоге будет выполняться Realm, после чего RealmgetAuthenticationInfo(token)
метод.
Этот метод в основном выполняет следующие операции:
- Проверьте отправленную информацию о токене для аутентификации
- Получить информацию о пользователе из источника данных (обычно из базы данных) на основе информации о токене.
- Сопоставьте и проверьте информацию о пользователе.
- Если проверка пройдена, она вернет инкапсулированную информацию о пользователе.
AuthenticationInfo
пример. - Брошен, если проверка не удалась
AuthenticationException
Информация об исключении.
Что нам нужно сделать в нашем приложении, так это настроить класс Realm, наследовать абстрактный класс AuthorizingRealm, перегрузить doGetAuthenticationInfo() и переопределить метод для получения информации о пользователе.
2: Реализация полномочий по ссылкам
Переопределите doGetAuthorizationInfo(), чтобы определить логику получения ролей и разрешений пользователя, а также оценить разрешения для shiro.
Полный код выглядит следующим образом
package com.example.demo.core.shiro;
import com.example.demo.model.UserInfo;
import com.example.demo.service.RolePermService;
import com.example.demo.service.UserInfoService;
import com.example.demo.service.UserRoleService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
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;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 自定义如何查询用户信息,如何查询用户的角色和权限,如何校验密码等逻辑
*/
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserInfoService userService;
@Autowired
private UserRoleService userRoleService;
@Autowired
private RolePermService rolePermService;
/**
* 告诉shiro如何根据获取到的用户信息中的密码和盐值来校验密码
*/
{
//设置用于匹配密码的CredentialsMatcher
HashedCredentialsMatcher hashMatcher = new HashedCredentialsMatcher();
hashMatcher.setHashAlgorithmName("md5");
hashMatcher.setStoredCredentialsHexEncoded(true);
//加密的次数
hashMatcher.setHashIterations(1024);
this.setCredentialsMatcher(hashMatcher);
}
/**
* 定义如何获取用户的角色和权限的逻辑,给shiro做权限判断
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
}
UserInfo user = (UserInfo) getAvailablePrincipal(principals);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(user.getRoles());
info.setStringPermissions(user.getPerms());
return info;
}
/**
* 定义如何获取用户信息的业务逻辑,给shiro做登录
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
if (username == null) {
throw new AccountException("Null usernames are not allowed by this realm.");
}
UserInfo userDB = userService.selectBy("userName",username);
if (userDB == null) {
throw new UnknownAccountException("No account found for admin [" + username + "]");
}
//查询用户的角色和权限存到SimpleAuthenticationInfo中,这样在其它地方
//SecurityUtils.getSubject().getPrincipal()就能拿出用户的所有信息,包括角色和权限
List<String> roleList = userRoleService.getRolesByUserId(userDB.getId());
List<String> permList = rolePermService.getPermsByUserId(userDB.getId());
Set<String> roles = new HashSet(roleList);
Set<String> perms = new HashSet(permList);
userDB.setRoles(roles);
userDB.setPerms(perms);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDB, userDB.getPassword(), getName());
info.setCredentialsSalt(ByteSource.Util.bytes(userDB.getSalt()));
return info;
}
}
Семь: добавить конфигурацию широ
Создать ядро→конфигуратор→Широконфигурер
package com.example.demo.core.configurer;
import com.example.demo.core.shiro.CustomRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class ShiroConfigurer {
/**
* 注入自定义的realm,告诉shiro如何获取用户信息来做登录或权限控制
*/
@Bean
public Realm realm() {
return new CustomRealm();
}
@Bean
public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
/**
* setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
* 在@Controller注解的类的方法中加入@RequiresRole注解,会导致该方法无法映射请求,导致返回404。
* 加入这项配置能解决这个bug
*/
creator.setUsePrefix(true);
return creator;
}
/**
* 这里统一做鉴权,即判断哪些请求路径需要用户登录,哪些请求路径不需要用户登录
* @return
*/
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();
chain.addPathDefinition( "/userInfo/selectById", "authc, roles[admin]");
chain.addPathDefinition( "/logout", "anon");
chain.addPathDefinition( "/userInfo/selectAll", "anon");
chain.addPathDefinition( "/userInfo/login", "anon");
chain.addPathDefinition( "/**", "authc");
return chain;
}
}
Широ предоставляет и ряд фильтров по умолчанию, мы можем использовать эти фильтры для настройки разрешений для управления указанным URL-адресом:
аббревиатура конфигурации | соответствующий фильтр | Функции |
---|---|---|
anon | AnonymousFilter | Указанный URL-адрес может быть доступен анонимно |
authc | FormAuthenticationFilter | Указанный URL-адрес требует входа в форму, которая будет получена из запроса по умолчанию.username ,password ,rememberMe Дождитесь параметров и попробуйте войти. Если вы не можете войти, он перейдет на путь, настроенный loginUrl. Мы также можем использовать этот фильтр в качестве логики входа по умолчанию, но обычно мы сами пишем логику входа в контроллер, а информацию, возвращаемую ошибкой, можно настроить, если мы напишем ее сами. |
authcBasic | BasicHttpAuthenticationFilter | Для указания URL-адреса требуется базовый вход в систему |
logout | LogoutFilter | Фильтр выхода, настройте указанный URL-адрес для реализации функции выхода из системы, что очень удобно. |
noSessionCreation | NoSessionCreationFilter | Отключить создание сеанса |
perms | PermissionsAuthorizationFilter | Требуется указанное разрешение на доступ |
port | PortFilter | Необходимо указать порт для доступа |
rest | HttpMethodPermissionFilter | Преобразуйте метод http-запроса в соответствующий глагол, чтобы создать строку разрешения. |
roles | RolesAuthorizationFilter | Требуется указанная роль для доступа |
ssl | SslFilter | Требуется HTTPS-запрос для доступа |
user | UserFilter | Для доступа требуется авторизованный пользователь или пользователь с функцией «запомнить меня». |
Восемь: добавьте метод входа в UserInfoController
@PostMapping("/login")
public RetResult<UserInfo> login(String userName, String password) {
Subject currentUser = SecurityUtils.getSubject();
//登录
try {
currentUser.login(new UsernamePasswordToken(userName, password));
}catch (IncorrectCredentialsException i){
throw new ServiceException("密码输入错误");
}
//从session取出用户信息
UserInfo user = (UserInfo) currentUser.getPrincipal();
return RetResponse.makeOKRsp(user);
}
Девятое: добавить данные разрешений в базу данных
INSERT INTO `sys_role` VALUES ('1', '财务', '负责发工资', 'cw', '2018-05-26 00:37:52', null, '0');
INSERT INTO `sys_role` VALUES ('2', '人事', '负责员工', 'rs', '2018-05-26 00:38:18', null, '0');
INSERT INTO `user_role` VALUES ('1', '1', '1');
INSERT INTO `user_role` VALUES ('2', '1', '2');
INSERT INTO `sys_perm` VALUES ('1', '创建', '创建权限', 'create', '2018-05-26 00:39:16', null, '0');
INSERT INTO `sys_perm` VALUES ('2', '删除', '删除权限', 'delete', '2018-05-26 00:39:39', null, '0');
INSERT INTO `sys_perm` VALUES ('3', '修改', '修改权限', 'update', '2018-05-26 00:39:58', null, '0');
INSERT INTO `sys_perm` VALUES ('4', '查询', '查询权限', 'select', '2018-05-26 00:40:16', null, '0');
INSERT INTO `role_perm` VALUES ('1', '1', '1');
INSERT INTO `role_perm` VALUES ('2', '2', '1');
INSERT INTO `role_perm` VALUES ('3', '1', '2');
INSERT INTO `role_perm` VALUES ('4', '2', '2');
INSERT INTO `role_perm` VALUES ('5', '3', '2');
INSERT INTO `role_perm` VALUES ('6', '4', '2');
Десять: добавить shiroUtilsController
package com.example.demo.controller;
import com.example.demo.core.ret.ServiceException;
import com.example.demo.model.UserInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("shiroUtils")
public class ShiroUtilsController {
@GetMapping("/noLogin")
public void noLogin() {
throw new UnauthenticatedException();
}
@GetMapping("/noAuthorize")
public void noAuthorize() {
throw new UnauthorizedException();
}
@PostMapping("/getNowUser")
public UserInfo getNowUser() {
UserInfo u = (UserInfo) SecurityUtils.getSubject().getPrincipal();
return u;
}
}
Одиннадцать: Добавить код исключения ошибки
package com.example.demo.core.ret;
/**
* @Description: 响应码枚举,参考HTTP状态码的语义
* @author 张瑶
* @date 2018/4/19 09:42
*/
public enum RetCode {
// 成功
SUCCESS(200),
// 失败
FAIL(400),
// 未认证(签名错误)
UNAUTHORIZED(401),
/** 未登录 */
UNAUTHEN(4401),
/** 未授权,拒绝访问 */
UNAUTHZ(4403),
// 服务器内部错误
INTERNAL_SERVER_ERROR(500);
public int code;
RetCode(int code) {
this.code = code;
}
}
Двенадцать: добавить перехват исключений
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new HandlerExceptionResolver() {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
RetResult<Object> result = new RetResult<Object>();
// 业务失败的异常,如“账号或密码错误”
if (e instanceof ServiceException) {
result.setCode(RetCode.FAIL).setMsg(e.getMessage()).setData(null);
LOGGER.info(e.getMessage());
} else if (e instanceof NoHandlerFoundException) {
result.setCode(RetCode.NOT_FOUND).setMsg("接口 [" + request.getRequestURI() + "] 不存在");
} else if (e instanceof UnauthorizedException) {
result.setCode(RetCode.UNAUTHEN).setMsg("用户没有访问权限").setData(null);
}else if (e instanceof UnauthenticatedException) {
result.setCode(RetCode.UNAUTHEN).setMsg("用户未登录").setData(null);
}else if (e instanceof ServletException) {
result.setCode(RetCode.FAIL).setMsg(e.getMessage());
} else {
result.setCode(RetCode.INTERNAL_SERVER_ERROR).setMsg("接口 [" + request.getRequestURI() + "] 内部错误,请联系管理员");
String message;
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s", request.getRequestURI(), handlerMethod.getBean().getClass().getName(), handlerMethod.getMethod()
.getName(), e.getMessage());
} else {
message = e.getMessage();
}
LOGGER.error(message, e);
}
responseResult(response, result);
return new ModelAndView();
}
});
}
Тринадцать: добавить конфигурацию пути широ
существуетapplication.properties
добавлено в
#shiro配置
#用户未登录
shiro.loginUrl=/shiroUtils/noLogin
#用户没有权限
shiro.unauthorizedUrl=/shiroUtils/noAuthorize
Четырнадцать: Тест
Введите localhost:8080/userInfo/selectAll
Мы видим, что можем получить данные
Введите localhost:8080/userInfo/selectById
затем войдите в систему
Посетите localhost:8080/userInfo/selectById еще раз, и мы увидим, что shiro вступил в силу.
Изменить права доступа пользователя, перезагрузка, повторно войти
chain.addPathDefinition( "/userInfo/selectById", "authc, roles[cw]");
Посетите localhost:8080/userInfo/selectById еще раз
Пятнадцать: Оптимизация
оптимизировать один: Разрешения не могут оставаться без изменений.Когда нам нужно изменить разрешения, нам нужно вручную изменить файл конфигурации широ, что явно неразумно. Лучший способ - хранить разрешения в базе данных и модифицировать базу данных при изменении
1: Создайте таблицу ресурсов URL и добавьте данные
CREATE TABLE `sys_permission_init` (
`id` varchar(255) NOT NULL,
`url` varchar(255) DEFAULT NULL COMMENT '程序对应url地址',
`permission_init` varchar(255) DEFAULT NULL COMMENT '对应shiro权限',
`sort` int(100) DEFAULT NULL COMMENT '排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `sys_permission_init` VALUES ('1', '/userInfo/login', 'anon', '1');
INSERT INTO `sys_permission_init` VALUES ('2', '/userInfo/selectAll', 'anon', '2');
INSERT INTO `sys_permission_init` VALUES ('3', '/logout', 'anon', '3');
INSERT INTO `sys_permission_init` VALUES ('4', '/**', 'authc', '0');
INSERT INTO `sys_permission_init` VALUES ('5', '/userInfo/selectAlla', 'authc, roles[admin]', '6');
INSERT INTO `sys_permission_init` VALUES ('6', '/sysPermissionInit/aaa', 'anon', '5');
Здесь мы должны позволить'/**'
всегда в конце, поэтому нужно добавитьsort
Сортировать
2: Генерируем маппер, дао, сервис, контроллер в соответствии с инструментом и добавляем нужные нам методы запроса
SysPermissionInitMapper.xml
<sql id="Base_Column_List">
id, url, permission_init, sort
</sql>
<select id="selectAllOrderBySort" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
from sys_permission_init
order by sort desc
</select>
SysPermissionInitMapper.java
List<SysPermissionInit> selectAllOrderBySort();
3: изменитьShiroConfigurer.java
Изменено следующим образом
package com.example.demo.core.configurer;
import com.example.demo.core.shiro.CustomRealm;
import com.example.demo.model.SysPermissionInit;
import com.example.demo.service.SysPermissionInitService;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.util.List;
@Configuration
public class ShiroConfigurer {
@Resource
private SysPermissionInitService sysPermissionInitService;
/**
* 注入自定义的realm,告诉shiro如何获取用户信息来做登录或权限控制
*/
@Bean
public Realm realm() {
return new CustomRealm();
}
@Bean
public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
/**
* setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
* 在@Controller注解的类的方法中加入@RequiresRole注解,会导致该方法无法映射请求,导致返回404。
* 加入这项配置能解决这个bug
*/
creator.setUsePrefix(true);
return creator;
}
/**
* 这里统一做鉴权,即判断哪些请求路径需要用户登录,哪些请求路径不需要用户登录
* @return
*/
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();
List<SysPermissionInit> list = sysPermissionInitService.selectAllOrderBySort();
for(int i = 0,length = list.size();i<length;i++){
SysPermissionInit sysPermissionInit = list.get(i);
chain.addPathDefinition(sysPermissionInit.getUrl(), sysPermissionInit.getPermissionInit());
}
return chain;
}
}
4: тест
Введите localhost:8080/userInfo/selectById
затем войдите в систему
Посетите localhost:8080/userInfo/selectById еще раз, и мы увидим, что shiro вступил в силу.
Изменить права доступа пользователя к базе данных, перезапустить, войти снова
UPDATE sys_permission_init
SET permission_init = 'authc, roles[cw]'
WHERE
id = 5
Посетите localhost:8080/userInfo/selectById еще раз
Оптимизация вторая: Каждый раз, когда мы изменяем информацию о разрешениях, нам нужно перезапускать сервер, что явно неразумно.
1: Создать ШироСервис
package com.example.demo.service;
import java.util.Map;
/**
* shiro 动态更新权限
*/
public interface ShiroService {
Map<String, String> loadFilterChainDefinitions();
/**
* 动态修改权限
*/
void updatePermission();
}
2: Создать ШироСервисИмпл
package com.example.demo.service.impl;
import com.example.demo.model.SysPermissionInit;
import com.example.demo.service.ShiroService;
import com.example.demo.service.SysPermissionInitService;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class ShiroServiceImpl implements ShiroService {
@Autowired
ShiroFilterFactoryBean shiroFilterFactoryBean;
@Autowired
SysPermissionInitService sysPermissionInitService;
/**
* 初始化权限
*/
@Override
public Map<String, String> loadFilterChainDefinitions() {
// 权限控制map.从数据库获取
Map<String, String> filterChainDefinitionMap = new HashMap<>();
List<SysPermissionInit> list = sysPermissionInitService.selectAllOrderBySort();
for (SysPermissionInit sysPermissionInit : list) {
filterChainDefinitionMap.put(sysPermissionInit.getUrl(),
sysPermissionInit.getPermissionInit());
}
return filterChainDefinitionMap;
}
/**
* 重新加载权限
*/
@Override
public void updatePermission() {
synchronized (shiroFilterFactoryBean) {
AbstractShiroFilter shiroFilter = null;
try {
shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean
.getObject();
} catch (Exception e) {
throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
}
PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
.getFilterChainResolver();
DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
.getFilterChainManager();
// 清空老的权限控制
manager.getFilterChains().clear();
shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
shiroFilterFactoryBean.setFilterChainDefinitionMap(loadFilterChainDefinitions());
// 重新构建生成
Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
for (Map.Entry<String, String> entry : chains.entrySet()) {
String url = entry.getKey();
String chainDefinition = entry.getValue().trim().replace(" ", "");
manager.createChain(url, chainDefinition);
}
System.out.println("更新权限成功!!");
}
}
}
3: Изменить shiroUtilsController
Добавьте следующий код
/**
* @Description: 重新加载shiro权限
* @throws Exception
*/
@PostMapping("/updatePermission")
public void updatePermission() throws Exception {
shiroService.updatePermission();
}
4: тест
Введите localhost:8080/userInfo/selectById
разрешение на редактирование
UPDATE sys_permission_init
SET permission_init = 'authc, roles[cw1]'
WHERE
id = 5
Введите localhost:8080/shiroUtils/updatePermission для перезагрузки разрешений.
Примечание. На данный момент мы не модифицировали никакую часть программы и не перезапускали сервер.
Введите localhost:8080/userInfo/selectById
успех!
Дополнение: Генерация зашифрованного пароля пользователя
Файл находится в core→utils→test.java
public static void main(String []ages ){
//加密方式
String hashAlgorithmName = "md5";
//原密码
String credentials = "123456";
//加密次数
int hashIterations = 1024;
//加密盐值,大家可以用生成字符串的方法
String hash = "wxKYXuTPST5SG0jMQzVPsg==";
ByteSource credentialsSalt = ByteSource.Util.bytes(hash);
String password = new SimpleHash(hashAlgorithmName, credentials, credentialsSalt, hashIterations).toHex();
System.out.println(password);
}
адрес проекта
Адрес облака кода:git ee.com/bean также/no SPR…
Адрес гитхаба:GitHub.com/my bean also/no s…
Писать статьи непросто, если это вам поможет, нажмите звездочку
конец
Завершена функция добавления интерфейса защиты разрешений широ, а последующие функции будут обновляться одна за другой.Если у вас есть какие-либо вопросы, свяжитесь со мной по адресу mr_beany@163.com. Также попросите руководства у всех великих богов, спасибо всем.