数据库的脚本我就不贴上去了,如果你们想要的话可以加我QQ_2548152658
第一步引入pom依赖
pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<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.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--整合shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
整合shiro的话只需要引入shiro-spring-boot-starter就好了,他已经集成了shiro的功能了
我就把关键性的代码贴出来就好了,实体类,这些我就不再贴了,要的话找我就好了
自定义的认证器:
package com.hhh.springbootshiro.config;
import com.hhh.springbootshiro.entity.Permission;
import com.hhh.springbootshiro.entity.Role;
import com.hhh.springbootshiro.entity.User;
import com.hhh.springbootshiro.service.UserService;
import org.apache.shiro.authc.*;
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.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @Description: 自定义认证器 shiro的授权和认证
* @Author: hhh
* @CreateDate:
* @UpdateUser: hhh
* @UpdateDate:
*/
public class AuthRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 授权
* 拿到对应的用户名,根据用户拿到角色和权限的名字
* @author hhh
* @return
* @exception
* @date 2019/3/28 14:35
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User) principalCollection.fromRealm(this.getClass().getName()).iterator().next();
Set<Role> roles = user.getRoles();
List<String> rolelist=new ArrayList<>();
List<String> permissionList=new ArrayList<>();
//CollectionUtils.isEmpty() 判断这是不是个集合
if(!CollectionUtils.isEmpty(roles)){
for (Role role : roles) {
rolelist.add(role.getRoleName());
rolelist.add(role.getDescription());
Set<Permission> permissions = role.getPermissions();
if(!CollectionUtils.isEmpty(permissions)){
for (Permission permission : permissions) {
permissionList.add(permission.getName());
permissionList.add(permission.getPid());
permissionList.add(permission.getUrl());
permissionList.add(String.valueOf(permission.getIsmenu()).toString());
}
}
}
}
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addRoles(rolelist);
info.addStringPermissions(permissionList);
return info;
}
/**
* 认证
* @author hhh
* @return
* @exception
* @date 2019/3/28 14:35
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//token携带了用户信息
UsernamePasswordToken usernamePasswordToken= (UsernamePasswordToken) token;
//获取前段输入的用户名
String username = usernamePasswordToken.getUsername();
//根据用户名查询数据库中对应的记录 连表查询出来的所有东西 用户 角色 菜单
User user = userService.findUserByUsername(username);
//当前realm对象的name
String realmName=getName();
//盐值
ByteSource bytes = ByteSource.Util.bytes(user.getSalt());
//封装用户信息,构建AuthenticationInfo对象并返回
AuthenticationInfo autInfo=new SimpleAuthenticationInfo(user,user.getPassword(),bytes,realmName);
return autInfo;
}
}
shiro的Config配置:
package com.hhh.springbootshiro.config;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.LinkedHashMap;
@Configuration
public class ShiroConfig {
/**
* 密码校验规则HashedCredentialsMatcher
* 这个类是为了对密码进行编码的 ,
* 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
* 这个类也负责对form里输入的密码进行编码
* 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
* @author hhh
* @return
* @exception
* @date 2019/3/28 15:40
*/
@Bean("hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
//指定加密方式为MD5
credentialsMatcher.setHashAlgorithmName("MD5");
//加密次数
credentialsMatcher.setHashIterations(1024);
credentialsMatcher.setStoredCredentialsHexEncoded(true);
return credentialsMatcher;
}
@Bean("authRealm")
@DependsOn("lifecycleBeanPostProcessor")
public AuthRealm authRealm(@Qualifier("hashedCredentialsMatcher")HashedCredentialsMatcher hashedCredentialsMatcher){
AuthRealm authRealm=new AuthRealm();
authRealm.setAuthorizationCachingEnabled(false);
authRealm.setCredentialsMatcher(hashedCredentialsMatcher);
return authRealm;
}
/**
* 定义安全管理器securityManager,注入自定义的realm
* @author hhh
* @return
* @exception
* @date 2019/3/28 16:12
*/
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm){
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(authRealm);
return manager;
}
/**
* 定义shiroFilter过滤器并注入securityManager
* @param securityManager
* @return
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
bean.setLoginUrl("/login");
bean.setSuccessUrl("/index");
bean.setUnauthorizedUrl("/login");
LinkedHashMap<String,String> map=new LinkedHashMap<>();
map.put("/index","authc");
map.put("/login","anon");
//角色为admin的用户才能访问admin网页
//map.put("/admin", "roles[admin]");
map.put("/**","user");
bean.setFilterChainDefinitionMap(map);
return bean;
}
/**
* Spring的一个bean , 由Advisor决定对哪些类的方法进行AOP代理 .
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
/**
* 配置shiro跟spring的关联
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
/**
* lifecycleBeanPostProcessor是负责生命周期的 , 初始化和销毁的类
* (可选)
*/
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
public static void main(String[] args) {
String hashAlgorithName = "MD5";
String password = "123456";
int hashIterations = 1024;//加密次数
ByteSource credentialsSalt = ByteSource.Util.bytes("admin");
Object obj = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations);
System.out.println(obj);
}
}
如果你配置过xml文件的话,可以根据xml文件来对应里面的每一个bean,这样你就很容易读懂的。
<!--配置自定义的Realm-->
<bean id="shiroRealm" class="com.hhh.ssm.shiro.MyRealm">
<property name="userService" ref="userService" />
<!--以下三个配置告诉shiro将如何对用户传来的明文密码进行加密-->
<property name="credentialsMatcher">
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--指定hash算法为MD5-->
<property name="hashAlgorithmName" value="md5"/>
<!--指定散列次数为1024次-->
<property name="hashIterations" value="1024"/>
<!--true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储-->
<property name="storedCredentialsHexEncoded" value="true"/>
</bean>
</property>
</bean>
<!--注册安全管理器-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroRealm" />
</bean>
<!--Shiro核心过滤器-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager" />
<!-- 身份验证失败,跳转到登录页面 -->
<property name="loginUrl" value="/login"/>
<!-- 身份验证成功,跳转到指定页面 -->
<!--<property name="successUrl" value="/index.jsp"/>-->
<!-- 权限验证失败,跳转到指定页面 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!-- Shiro连接约束配置,即过滤链的定义 -->
<property name="filterChainDefinitions">
<value>
<!--
注:anon,authcBasic,auchc,user是认证过滤器
perms,roles,ssl,rest,port是授权过滤器
-->
<!--anon 表示匿名访问,不需要认证以及授权-->
<!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
<!--roles[admin]表示角色认证,必须是拥有admin角色的用户才行-->
/user/login=anon
/user/updatePwd.jsp=authc
/admin/*.jsp=roles[4]
/user/teacher.jsp=perms["user:update"]
<!-- /css/** = anon
/images/** = anon
/js/** = anon
/ = anon
/user/logout = logout
/user/** = anon
/userInfo/** = authc
/dict/** = authc
/console/** = roles[admin]
/** = anon-->
</value>
</property>
</bean>
<!-- Shiro生命周期,保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>