网上有很多整合shiro的博客分享,但是貌似没找到一个完整,并且能够实现的。不是包的问题,就是代码的问题,也可能是自己的问题,或者版本的问题。所以,整理了一版自己已应用的.
org.springframework.boot
spring-boot-starter-parent
2.0.2.RELEASE
org.springframework.cloud
spring-cloud-dependencies
Finchley.RELEASE
pom
import
org.springframework.cloud
spring-cloud-starter-config
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-web
net.sourceforge.nekohtml
nekohtml
1.9.22
org.apache.shiro
shiro-spring
1.4.0
mysql
mysql-connector-java
5.1.35
com.alibaba
druid
1.0.11
org.projectlombok
lombok
true
com.alibaba
fastjson
1.2.47
commons-io
commons-io
2.4
org.apache.tomcat.embed
tomcat-embed-jasper
provided
javax.servlet
javax.servlet-api
provided
javax.servlet
jstl
import com.simple.users.dto.entity.UserInfo;
import com.simple.users.service.UserInfoService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;
public class MyShiroRealm extends AuthorizingRealm {
@Resource
private UserInfoService userInfoService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
UserInfo userInfo = (UserInfo) principals.getPrimaryPrincipal();
/*
* for (SysRole role : userInfo.getRoleList()) {
* authorizationInfo.addRole(role.getRole()); for (SysPermission p :
* role.getPermissions()) {
* authorizationInfo.addStringPermission(p.getPermission()); } }
*/
// 获取用户角色
Set roleSet = new HashSet();
roleSet.add("100002");
info.setRoles(roleSet);
// 获取用户权限
Set permissionSet = new HashSet();
permissionSet.add("权限添加");
permissionSet.add("权限删除");
info.setStringPermissions(permissionSet);
return info;
}
/**
* 主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。
*
* @param authcToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String username = token.getUsername();
UserInfo userInfo = userInfoService.findByUsername(username);
if (userInfo == null) {
return null;
}
String password = new String((char[]) token.getCredentials());
String pwdMd5 = (new Md5Hash(password, username)).toHex();
System.out.println("----->>pwdMd5====" + pwdMd5);
UserInfo user = new UserInfo();
user.setUsername(username);
user.setPassword(pwdMd5);
return new SimpleAuthenticationInfo(user, pwdMd5, ByteSource.Util.bytes(username), getName());
}
}
import com.simple.utils.Base64Util;
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.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
@Configuration
public class ShiroConfig {
/**
* ShiroDialect,为了在thymeleaf里使用shiro的标签的bean
* 开启thymeleaf模板访问,注释则使用配置的jsp或者HTML访问模式
* @return
*/
// @Bean
// public ShiroDialect shiroDialect() {
// return new ShiroDialect();
// }
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
System.out.println("--------ShiroConfiguration.shirFilter()");
// 添加安全管理器
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不设置默认会自动寻找Web工程根目录下的"/index.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/");
// 登录成功后要跳转的链接
// shiroFilterFactoryBean.setSuccessUrl("/?path=user/main");
// 添加shiro内置过滤器
/**
* anon:表示可以匿名使用。 authc:表示需要认证(登录)才能使用,没有参数
*
* roles:参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,
* 例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
*
* perms:参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,
* 例如/admins/user/**=perms["user:add:*,user:modify:*"],
* 当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
*
* rest:根据请求的方法,相当于/admins/user/**=perms[user:method]
* ,其中method为post,get,delete等。
*
* port:当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,
* 其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,
* queryString是你访问的url里的?后面的参数。 authcBasic:没有参数表示httpBasic认证
*
* ssl:表示安全的url请求,协议为https user:当登入操作时不做检查
*/
Map filterChainDefinitionMap = new LinkedHashMap();
// 静态资源的处理
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/plugins/**", "anon");
// // 请求路径的处理
filterChainDefinitionMap.put("/H-PLE/**", "authc");
// 退出系统的过滤器
filterChainDefinitionMap.put("/userInfo/logout", "logout");
filterChainDefinitionMap.put("/userInfo/login", "anon");
// 默认所有资源必须认证才能访问
filterChainDefinitionMap.put("/**", "authc");
// 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 )
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(1);// 散列的次数(默认一次),比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
// 注入记住我管理器;
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* cookie对象;
*
* @return
*/
public SimpleCookie rememberMeCookie() {
// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//
simpleCookie.setMaxAge(2592000);
return simpleCookie;
}
/**
* cookie管理对象;记住我功能
*
* @return
*/
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
// rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
try {
cookieRememberMeManager.setCipherKey(Base64Util.decode("3AvVhmFLUs0KTA3Kprsdag=="));
} catch (Exception e) {
e.printStackTrace();
}
return cookieRememberMeManager;
}
/**
* 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean(name = "simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");// 数据库异常处理
mappings.setProperty("UnauthorizedException", "403");
r.setExceptionMappings(mappings); // None by default
r.setDefaultErrorView("error"); // No default
r.setExceptionAttribute("ex"); // Default is "exception"
// r.setWarnLogCategory("example.MvcLogger"); // No default
return r;
}
}
@ResponseBody
@RequestMapping(value = "/login", method = RequestMethod.POST, produces = { "application/json; charset=UTF-8" })
public Object login(@RequestBody JSONObject jsonP) {
JSONObject result = new JSONObject();
JSONObject resultHd = new JSONObject();
JSONObject resultBd = new JSONObject();
String userName = Null.nullToSpace(jsonP.getString("userName"));
String passWord = Null.nullToSpace(jsonP.getString("passWord"));
Boolean rememberMe = jsonP.getBoolean("agree");
System.out.println("userName--" + userName + "; passWord--" + passWord + "; rememberMe--" + rememberMe);
UsernamePasswordToken token = new UsernamePasswordToken(userName, passWord, rememberMe);
try {
SecurityUtils.getSubject().login(token);
resultHd.put("error", "成功");
resultHd.put("errorCode", "0");
resultHd.put("data", new HashMap());
} catch (UnknownAccountException e) {
resultHd.put("error", "失败");
resultHd.put("errorCode", "2");
resultHd.put("data", new HashMap());
e.printStackTrace();
} catch (IncorrectCredentialsException e) {
resultHd.put("error", "失败");
resultHd.put("errorCode", "3");
resultHd.put("data", new HashMap());
e.printStackTrace();
} catch (AuthenticationException e) {
// 其他错误,比如锁定,如果想单独处理请单独catch处理
resultHd.put("error", "失败");
resultHd.put("errorCode", "1");
resultHd.put("data", new HashMap());
e.printStackTrace();
}
result.put("header", resultHd);
result.put("body", resultBd);
return result;
}
权限类:SysPermission.java
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
@Getter
@Setter
@ToString
@Entity
public class SysPermission implements Serializable {
@Id
@GeneratedValue
private Integer id;// 主键.
private String name;// 名称.
@Column(columnDefinition = "enum('menu','button')")
private String resourceType;// 资源类型,[menu|button]
private String url;// 资源路径.
private String permission; // 权限字符串,menu例子:role:*,button例子:role:create,role:update,role:delete,role:view
private Long parentId; // 父编号
private String parentIds; // 父编号列表
private Boolean available = Boolean.FALSE;
@ManyToMany
@JoinTable(name = "SysRolePermission", joinColumns = { @JoinColumn(name = "permissionId") }, inverseJoinColumns = {
@JoinColumn(name = "roleId") })
private List roles;
}
----------------------------------------------------------------------------------------
角色类:SysRole.java
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.util.List;
@Getter
@Setter
@ToString
@Entity
public class SysRole {
@Id
@GeneratedValue
private Integer id; // 编号
private String role; // 角色标识程序中判断使用,如"admin",这个是唯一的:
private String description; // 角色描述,UI界面显示使用
private Boolean available = Boolean.FALSE; // 是否可用,如果不可用将不会添加给用户
// 角色 -- 权限关系:多对多关系;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "SysRolePermission", joinColumns = { @JoinColumn(name = "roleId") }, inverseJoinColumns = {
@JoinColumn(name = "permissionId") })
private List permissions;
// 用户 - 角色关系定义;
@ManyToMany
@JoinTable(name = "SysUserRole", joinColumns = { @JoinColumn(name = "roleId") }, inverseJoinColumns = {
@JoinColumn(name = "uid") })
private List userInfos;// 一个角色对应多个用户
// 省略 get set 方法
}
----------------------------------------------------------------------------------------
用户类:UserInfo.java
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
@Getter
@Setter
@ToString
@Entity
public class UserInfo implements Serializable {
@Id
@GeneratedValue
private Integer uid;
@Column(unique = true)
private String username;// 帐号
private String name;// 名称(昵称或者真实姓名,不同系统不同定义)
private String password; // 密码;
private String salt;// 加密密码的盐
private byte state;// 用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.
@ManyToMany(fetch = FetchType.EAGER) // 立即从数据库中进行加载数据;
@JoinTable(name = "SysUserRole", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns = {
@JoinColumn(name = "roleId") })
private List roleList;// 一个用户具有多个角色
/**
* 密码盐.
*
* @return
*/
public String getCredentialsSalt() {
return this.username + this.salt;
}
// 重新对盐重新进行了定义,用户名+salt,这样就更加不容易被破解
}
用户表:账号admin 密码admin
INSERT INTO `user_info`(`uid`, `name`, `password`, `salt`, `state`, `username`) VALUES (1, '管理员', 'f6fdffe48c908deb0f4c3bd36c032e72', '87', 0, 'admin');
权限表:
INSERT INTO `sys_permission`(`id`, `available`, `name`, `parent_id`, `parent_ids`, `permission`, `resource_type`, `url`) VALUES (1, b'0', '用户管理', 0, '0/', 'userInfo:view', 'menu', 'userInfo/userList');
INSERT INTO `sys_permission`(`id`, `available`, `name`, `parent_id`, `parent_ids`, `permission`, `resource_type`, `url`) VALUES (2, b'0', '用户添加', 1, '0/1', 'userInfo:add', 'button', 'userInfo/userAdd');
INSERT INTO `sys_permission`(`id`, `available`, `name`, `parent_id`, `parent_ids`, `permission`, `resource_type`, `url`) VALUES (3, b'0', '用户删除', 1, '0/1', 'userInfo:del', 'button', 'userInfo/userDel');
角色表:
INSERT INTO `sys_role`(`id`, `available`, `description`, `role`) VALUES (1, b'0', '管理员', 'admin');
INSERT INTO `sys_role`(`id`, `available`, `description`, `role`) VALUES (2, b'0', 'VIP会员', 'vip');
里面的Null类引用,可以在 https://blog.csdn.net/weixin_42614447/article/details/86536425 (Java 一些常用工具类)这里面找工具类。
druid:
stat:
mergeSql: true;
slowSqlMillis: 5000
logging:
level:
com: DEBUG
mybatis:
mapper-locations: classpath:com/simple/*/dto/maps/*Mapper.xml
type-aliases-package: com.simple.*
server:
port: 8081
servlet:
context-path: /
spring:
datasource:
driverClassName: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3306/oa?characterEncoding=utf8&autoReconnect=true&useSSL=false&useAffectedRows=true
username: root
password: root
filters: stat,wall,log4j
initialSize: 5
maxActive: 20
maxPoolPreparedStatementPerConnectionSize: 20
maxWait: 60000
minEvictableIdleTimeMillis: 300000
minIdle: 5
poolPreparedStatements: true
testOnBorrow: false
testOnReturn: false
testWhileIdle: true
timeBetweenEvictionRunsMillis: 60000
validationQuery: SELECT 1 FROM DUAL
http:
encoding:
charset: UTF-8
enabled: true
jpa:
show-sql: true
hibernate:
ddl-auto: update
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
mvc:
locale: zh_CN
view:
prefix: /WEB-INF/jsp/
suffix: .jsp
static-path-pattern: /**
#资源名称md5方式
resources:
chain:
strategy:
content:
enabled: true
paths: /**
以上就是shiro完整代码,如有疑问,随时评论.
转载请注明出处!