



<!--thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
4. 编写前端页面 在templates目录下编写 login.html,add.html,delete.html,index.html 导入thymeleaf的dtd
xmlns:th="http://www.thymeleaf.org"login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form th:action="login">
<input type="text" name="username" value="">
<input type="password" name="password" value="">
<input type="submit" value="登录">
</form>
</body>
</html>index.html

add.html

delete.html

5. 编写controller,跳转到登录页面的方法

@RequestMapping({"/","tologin"})
public String tologin(){
return "login";
}

<!--shiro-整合spring的包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.2</version>
</dependency>
<!--shiro整合thymeleaf-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

##配置数据驱动信息 (key固定)
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql:///spring_shiro
spring.datasource.username = root
spring.datasource.password =123456在application.properties中添加数据库信息


mapper:

service:

Impl:

controller:测试是否能够查询到





@Configuration
public class shiroConfig {
/**
* 密码校验规则HashedCredentialsMatcher
* 这个类是为了对密码进行编码的 ,
* 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
* 这个类也负责对form里输入的密码进行编码
* 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
*/
@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 matcher) {
AuthRealm authRealm = new AuthRealm();
authRealm.setAuthorizationCachingEnabled(false);
authRealm.setCredentialsMatcher(matcher);
return authRealm;
}
//3. shiroFilterfactaryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);//设置安全管理器
shiroFilterFactoryBean.setLoginUrl("/toLogin");//没有认证后跳到的页面
/**
* shiro的内置过滤器
anon:无需认证就可以访问 默认
authc:必须认证了才能访问
user:必须拥有记住我功能才能访问
perms:必须拥有对某个的权限才能访问
role:拥有某个角色权限才能访问
*/
//添加shiro的内置过滤器 设置要拦截的url
Map<String,String> filterChainDefinitionMap=new LinkedHashMap<>();//拦截
filterChainDefinitionMap.put("/add","authc");// /add请求必须认证才能访问
filterChainDefinitionMap.put("/del","authc");//del必须认证才能访问
// filterChainDefinitionMap.put("user/**","authc");//支持通配符
//授权
filterChainDefinitionMap.put("/add","perms[user:add]");//没有这个user:add权限的会被拦截下来
filterChainDefinitionMap.put("/del","perms[user:delete]");//没有这个user:delete权限的会被拦截下来
//未授权的跳转的url
shiroFilterFactoryBean.setUnauthorizedUrl("/Unauthorized");
//设置注销的url
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);//把设置好的过滤设置到ShiroFilterFactoryBean
return shiroFilterFactoryBean;
}
//2. DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm对象 userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1. 创建realm对象 自定义的·类
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
//整合shiroDialect:用来整合shiro-thymeleaf
@Bean
public ShiroDialect getshiroDialect(){
return new ShiroDialect();
}
/**
* Spring的一个bean , 由Advisor决定对哪些类的方法进行AOP代理 .
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
}完整版
@Configuration
public class ShiroConfiguration {
/**
* 密码校验规则HashedCredentialsMatcher
* 这个类是为了对密码进行编码的 ,
* 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
* 这个类也负责对form里输入的密码进行编码
* 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
*/
@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 matcher) {
AuthRealm authRealm = new AuthRealm();
authRealm.setAuthorizationCachingEnabled(false);
authRealm.setCredentialsMatcher(matcher);
return authRealm;
}
/**
* 定义安全管理器securityManager,注入自定义的realm
* @param authRealm
* @return
*/
@Bean("securityManager")
public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(authRealm);
return manager;
}
/**
* 定义shiroFilter过滤器并注入securityManager
* @param manager
* @return
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置securityManager
bean.setSecurityManager(manager);
//设置登录页面
//可以写路由也可以写jsp页面的访问路径
bean.setLoginUrl("/login");
//设置登录成功跳转的页面
bean.setSuccessUrl("/pages/index.jsp");
//设置未授权跳转的页面
bean.setUnauthorizedUrl("/pages/unauthorized.jsp");
//定义过滤器
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/index", "authc");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/loginUser", "anon");
filterChainDefinitionMap.put("/admin", "roles[admin]");
filterChainDefinitionMap.put("/edit", "perms[delete]");
filterChainDefinitionMap.put("/druid/**", "anon");
//需要登录访问的资源 , 一般将/**放在最下边
filterChainDefinitionMap.put("/**", "authc");
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
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 class UserRealm extends AuthorizingRealm {
@Autowired
InfoService service;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权 doGetAuthorizationInfo");
SimpleAuthorizationInfo simpInfo = new SimpleAuthorizationInfo();
//获取当前用户的对象
Subject subject=SecurityUtils.getSubject();
Info user = (Info)subject.getPrincipal();//获取用户信息
simpInfo.addStringPermission(user.getPerm());//获取数据库权限
return simpInfo;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证 doGetAuthorizationInfo");
//获取当前的用户
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken userToken=(UsernamePasswordToken)authenticationToken;//获取登录的信息
//获取用户名 密码 数据库取
System.out.println(userToken.getUsername());
Info query = service.queryByName(userToken.getUsername());
System.out.println(query);
if(query==null){//没有这个用户
return null;
}
Session session=subject.getSession();//获取用户的session
session.setAttribute("loginuser",query);
if(!userToken.getUsername().equals(query.getUsername())){//判断登录的用户名密码 匹配数据库是否正确
return null;//抛出异常
}
//密码认证,shiro做
return new SimpleAuthenticationInfo(query,query.getPassword(),"");
}
}
完整版
public class AuthRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
/**
* 为用户授权
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取前端输入的用户信息,封装为User对象
User userweb = (User) principals.getPrimaryPrincipal();
//获取前端输入的用户名
String username = userweb.getUsername();
//根据前端输入的用户名查询数据库中对应的记录
User user = userService.findByUsername(username);
//如果数据库中有该用户名对应的记录,就进行授权操作
if (user != null){
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//因为addRoles和addStringPermissions方法需要的参数类型是Collection
//所以先创建两个collection集合
Collection<String> rolesCollection = new HashSet<String>();
Collection<String> perStringCollection = new HashSet<String>();
//获取user的Role的set集合
Set<Role> roles = user.getRoles();
//遍历集合
for (Role role : roles){
//将每一个role的name装进collection集合
rolesCollection.add(role.getName());
//获取每一个Role的permission的set集合
Set<Permission> permissionSet = role.getPermissions();
//遍历集合
for (Permission permission : permissionSet){
//将每一个permission的name装进collection集合
perStringCollection.add(permission.getName());
}
//为用户授权
info.addStringPermissions(perStringCollection);
}
//为用户授予角色
info.addRoles(rolesCollection);
return info;
}else{
return null;
}
}
/**
* 认证登录
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//token携带了用户信息
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
//获取前端输入的用户名
String userName = usernamePasswordToken.getUsername();
//根据用户名查询数据库中对应的记录
User user = userService.findByUsername(userName);
//当前realm对象的name
String realmName = getName();
//盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());
//封装用户信息,构建AuthenticationInfo对象并返回
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
credentialsSalt, realmName);
return authcInfo;
}
}
@RequestMapping("/login")
public String login(String username,String password){
try {
//获取当前的用户
Subject subject = SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
subject.login(usernamePasswordToken);//执行登录的方法 没有异常就成功了
return "index";
} catch (UnknownAccountException e) {
/**
* 异常信息
* UnknownAccountException :用户名不存在
* IncorrectCredentialsException:密码错误
*/
e.printStackTrace();
System.out.println("用户名不存在");
}catch (IncorrectCredentialsException e){
System.out.println("密码错误");
}
return "login";
}
@RequestMapping("/add")
public String add(){//跳转页面
return "add";
}
@RequestMapping("/del")
public String delete(){//跳转页面
return "delete";
}
@RequestMapping("/Unauthorized")
public String Unauthorized(){//没有权限跳转的url
return "Unauthorized";
}
//注销
@RequestMapping("/logout")
public String logout() {
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("loginuser",null);//清空session
return "login";
}


root用户只有user:delete权限 所以只能看到删除按钮


dj用户只有user:add权限 只能看到添加


ss用户什么权限也没有 所以什么按钮也看不见
其中还有加密方式 比如md5 可以自行添加 就不一一介绍了
重点:shiroConfig类和UserRealm类配置好 核心**