Shiro
1 自定义realm,认证,授权
所需要pom的依赖:shiro-core, shiro-spring, mybatis-spring-boot-starter, mysql-connector-java, spring-boot-starter-thymeleaf, aspectjweaver
application.yml配置文件
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.java502.shirodemo502.pojo
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/shrio?useUnicode=true&characterEncoding=utf8
username: root
password: 123123
MyRealm.java
@Component
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
// 授权的方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 去数据库(Redis)
// 拿到用户名
String userName = (String) principalCollection.getPrimaryPrincipal();
// 获取用户对象
User user = getUserByUserName(userName);
// 获取权限信息
Set<String> permissions = getPermissionByUser(user);
// 获取角色数据
Set<String> roles = getRoleByUser(user);
// 返回授权信息
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setStringPermissions(permissions);
authorizationInfo.setRoles(roles);
return authorizationInfo;
}
/**
* 获取角色数据
*/
private Set<String> getRoleByUser(User user) {
Set<String> roles = new HashSet<>();
roles.add(user.getRole().getRoleName());
return roles;
}
/**
* 获取权限数据
*/
private Set<String> getPermissionByUser(User user) {
Set<String> permissions = new HashSet<>();
// 获取权限列表
List<Access> accessList = user.getRole().getAccessList();
for (Access access : accessList) {
permissions.add(access.getAccessUrl());
}
return permissions;
}
/**
* 获取用户对象
*/
private User getUserByUserName(String userName) {
if(userName == null || userName.isEmpty()){
return null;
}
return userService.getUser(userName);
}
/**
* 认证的方法(登陆)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 通过token去获取用户名
String userName = (String) authenticationToken.getPrincipal();
// 通过查询数据库得到对应的用户信息
String pwd = getPwdByUserName(userName);
if (pwd == null) {
return null;
}
// 认证信息
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userName, pwd, "myRealm");
// 设置加盐
info.setCredentialsSalt(ByteSource.Util.bytes("java502"));
return info;
}
/**
* 通过用户名查询用户密码
*/
private String getPwdByUserName(String userName) {
if(userName == null || userName.isEmpty()) {
return null;
}
User user = userService.getUser(userName);
if(user == null) {
return null;
}
return user.getUserPwd();
}
}
RoleMapper.java:Role findById(@Param(“roleId”) Integer roleId);
RoleAccessMapper.java:List< Access> findAccessByRoleId(@Param(“roleId”) Integer roleId);
UserMapper.java
@Mapper
public interface UserMapper {
/**
* 查询所有
*/
List<User> findAll();
/**
* 通过用户名来查询用户信息
*/
User findByUserName(@Param("userName") String userName);
}
UserMapper.xml
<select id="findAll" resultType="com.java502.shirodemo502.pojo.User">
select * from user
</select>
<resultMap id="userMap" type="com.java502.shirodemo502.pojo.User">
<id property="id" column="id"/>
<result property="userName" column="userName"/>
<result property="userPwd" column="userPwd"/>
<result property="userPhone" column="userPhone"/>
<result property="userAddTime" column="userAddTime"/>
<result property="roleId" column="roleId"/>
<association property="role" column="roleId" javaType="com.java502.shirodemo502.pojo.Role" select="com.java502.shirodemo502.dao.RoleMapper.findById"/>
</resultMap>
<!--通过用户名查询信息-->
<select id="findByUserName" resultMap="userMap">
select * from user where userName=#{userName}
</select>
UserServiceImpl.java
@Service
@Transactional(rollbackFor = Exception.class)
@SuppressWarnings("all")
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUser(String userName) {
return userMapper.findByUserName(userName);
}
}
登录案例
自带退出功能:
<a th:href="@{/logout}">退出</a>
注解权限控制
2 加密,过滤器,记住我的功能
自带的
自定义过滤器
@Configuration
public class ShiroConfig {
/**
* 加密算法
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");
matcher.setHashIterations(1);
return matcher;
}
/**
* 自定义realm
*/
@Bean
public MyRealm myRealm1(){
MyRealm myRealm = new MyRealm();
myRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myRealm;
}
/**
* 安全管理器
*/
@Bean
public SecurityManager securityManager(){
// web环境的安全管理器
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm1());
// 设置记住我
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* shiro的过滤器
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager());
// 配置拦截器
// 配置不会被拦截的链接 顺序判断,因为前端模板采用了 thymeleaf,
Map<String,String> filterChainDefinitionMap = new HashMap<>(16);
// 这里不能直接使用 ("/static/**", "anon")来配置匿名访问,必须配置到每个静态目录
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
//配置退出 过滤器,其中的具体的退出代码 Shiro 已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
// 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
// authc:所有 url 都必须认证通过才可以访问; anon:所有 url 都都可以匿名访问-->
filterChainDefinitionMap.put("/user/login","anon");
filterChainDefinitionMap.put("/user/login_page","anon");
filterChainDefinitionMap.put("/member/testRole","roles[学生管理]");
filterChainDefinitionMap.put("/member/testPer","permsOr[member:testPer,member:testPer2]");
// 其余所有的访问都需要认证(登陆才可以访问)
filterChainDefinitionMap.put("/**", "user");
// 如果不设置默认会自动寻找 Web 工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/user/login_page");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
//注入自定义的filter
// 用一个map来装自定义的filter
Map<String, Filter> filterMap = new HashMap<>(16);
filterMap.put("permsOr",permsOr());
// 交给shiroFilterFactoryBean
shiroFilterFactoryBean.setFilters(filterMap);
return shiroFilterFactoryBean;
}
// 自定义的filter or
@Bean
public PermsOrFilter permsOr(){
return new PermsOrFilter();
}
// cookie对象
@Bean
public SimpleCookie cookie(){
// 创建cookie对象
SimpleCookie cookie = new SimpleCookie();
// 设置时间
cookie.setMaxAge(3600);
cookie.setName("hsj");
return cookie;
}
// 记住我的管理器
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
// 设置cookie
rememberMeManager.setCookie(cookie());
// 设置加密
rememberMeManager.setCipherKey(Base64.decode("cXdlcnQxMjNxd2VydDEyMw=="));
return rememberMeManager;
}
// 管理shiro相关bean的声明周期
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
// 切面的代理
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
PermsOrFilter .java
// or 的权限过滤器
public class PermsOrFilter extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
// 获取主体
Subject subject = SecurityUtils.getSubject();
// 得到权限数组
String[] perms = (String[]) o;
// 判断权限是否为空
if(perms == null || perms.length == 0){
return true;
}
// or 的逻辑处理
for (String perm : perms) {
// 利用主体去判断是否有对应的权限
if (subject.isPermitted(perm)) {
return true;
}
}
return false; // 返回false 表示没有权限
}
}