org.apache.shiro shiro-spring1.4.0 org.springframework.boot spring-boot-starter-thymeleafmysql mysql-connector-javaorg.mybatis.spring.boot mybatis-spring-boot-starter2.1.2 com.alibaba druid-spring-boot-starter1.1.10
二 配置application.yml
server:
port: 8080
servlet:
session:
tracking-modes: cookie
spring:
datasource:
username: root
password: 6666
url: jdbc:mysql:///shiro?serverTimezone=Asia/Shanghai&characterEncoding=utf8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
thymeleaf:
encoding: UTF-8
servlet:
content-type: text/html
cache: false
prefix: classpath:/templates
suffix: .html
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
三 编写 shirorealm 来获取数据
package com.qf.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class ShiroRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
四 编写shiroConfig 编写配置类 创建所需对象 和环境
package com.qf.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.qf.realm.ShiroRealm;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
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 java.util.linkedHashMap;
@Configuration //相当于配置文件
public class ShiroConfig {
//realm域对象
public ShiroRealm getShiroRealm(){
return new ShiroRealm();
}
//安全管理对象 设置securitymanager环境
@Bean
public SecurityManager getSecurityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(getShiroRealm());
return securityManager;
}
//Shiro过滤器配置 必须书写过滤器 将manager设置里
//注意配置过滤路径的顺序
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
//创建Shiro工厂对象
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//未认证访问页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//认证成功跳转页面(一般不设置,默认登录成功跳转当前页面)
//shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权访问页面
shiroFilterFactoryBean.setUnauthorizedUrl("/refuse");
//通过map配置访问流程(顺序很重要)
linkedHashMap map = new linkedHashMap<>();
//配置静态资源
map.put("/js/**","anon");
map.put("/css/**","anon");
map.put("/jquery/**","anon");
map.put("/layui/**","anon");
//配置login页面
map.put("/login","anon");
//配置logout退出
//map.put("/logout","logout");
//配置授权
//map.put("/delete","perms[user:delete]");
//map.put("/select","perms[user:select]");
//user设置记住我(二次登录不做认证操作)
//map.put("/index","user");
map.put("/**","authc");//该路径认证后才能访问
//map.put("/**","anon");//所有路径都可以匿名访问
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
}
过滤器简称 对应的java类 anon org.apache.shiro.web.filter.authc.AnonymousFilter authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter port org.apache.shiro.web.filter.authz.PortFilter rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter ssl org.apache.shiro.web.filter.authz.SslFilter user org.apache.shiro.web.filter.authc.UserFilter logout org.apache.shiro.web.filter.authc.LogoutFilter
顺序 anon:admins/**=anon 没有参数,表示可以匿名使用。 authc:/admins/user/**=authc表示需要认证(登录)才能使用,FormAuthenticationFilter是表单认证,没有参数 roles:/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。 perms:/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。 rest:/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。 port:/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。 authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证 ssl:/admins/user/**=ssl没有参数,表示安全的url请求,协议为https user:/admins/user/**=user没有参数表示必须存在用户, 身份认证通过或通过记住我认证通过的可以访问,当登入操作时不做检查
五 创建controlleranon,authcBasic,authc,user是认证过滤器
perms,roles,ssl,rest,port是授权过滤器
package com.qf.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("toLogin")
public String toLgoin(){
System.out.println("toLogin");
return "/login";
}
@RequestMapping("login")
public String login(){
System.out.println("login");
return "/login";
}
@RequestMapping("refuse")
public String refuse(){
System.out.println("refuse");
return "/refuse";
}
@RequestMapping("index")
public String index(){
System.out.println("index");
return "/index";
}
@RequestMapping("add")
public String add(){
System.out.println("add");
return "/add";
}
@RequestMapping("select")
public String select(){
System.out.println("select");
return "/select";
}
@RequestMapping("delete")
public String delete(){
System.out.println("delete");
return "/delete";
}
// @RequestMapping("logout")
// public String logout(){
// System.out.println("logout");
// Subject subject = SecurityUtils.getSubject();
// subject.logout();
// return "/login";
// }
}
六 编写HTML
login.html
Title
refuse.html
Title 拒绝访问!!!
index.html
Title 主页面 添加用户 查询用户 删除用户 修改用户 退出
add.html
Title 添加用户
select.html
Title 查询用户
delete.html
七实现用户认证,修改UserController中的login方法Title 删除用户
@RequestMapping("login")
public String login(User user){
System.out.println("login");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(User.getUserName(), User.getPassword);
subject.login(token);
boolean authenticated = subject.isAuthenticated();
if(authenticated){
return "/index";
}
return "/login";
}
八修改ShiroRealm中的AuthenticationInfo方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String usercode = (String) token.getPrincipal();
String password2 = new String((char[]) token.getCredentials());
String password = new Md5Hash(password2).toString();
com.entity.User user = userService.findUser(usercode, password);
if (user != null) {
if (user.getUsercode().equals(usercode) && user.getPassword().equals(password)) {
SimpleAuthenticationInfo simpleAuthenticationInfo =
new SimpleAuthenticationInfo(usercode, password2, "my");//必须是前端传过来的密码
return simpleAuthenticationInfo;
} else {
return null;
}
}
return null;
}
}
九实现用户授权,在ShiroConfig中的shiroFilter方法中添加被授权的信息
//配置授权
map.put("/delete","perms[user:delete]");
map.put("/select","perms[user:select]");
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
HashSet
set.add("user:select");
set.add("user:update");
simpleAuthorizationInfo.addStringPermissions(set);
return simpleAuthorizationInfo;
}
thymeleaf-extras-shiro
在config
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
3.修改index.HTML
Title
主页面
添加用户
查询用户
删除用户
//shiro 如果没有权限 看不见
修改用户
退出
十二 退出
在index.HTML 加退出
shiro过滤器 //配置退出
map.put("/logout","logout");
在login.HTML 页面
记住我
UserController中的login中配置rememberMe
@RequestMapping("login")
public String login(String username, String password,boolean rememberMe){
System.out.println("login");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password,rememberMe);
subject.login(token);
boolean authenticated = subject.isAuthenticated();
if(authenticated){
return "/index";
}
return "/login";
}
在shiroConfig类中添加相关的方法
package com.qf.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.qf.realm.ShiroRealm;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
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 java.util.linkedHashMap;
@Configuration
public class ShiroConfig {
@Bean //3
public cookieRememberMeManager getcookieRememberMeManager(){
Simplecookie simplecookie = new Simplecookie("renemberMe");
simplecookie.setMaxAge(3600*24*31);
cookieRememberMeManager cookieRememberMeManager = new cookieRememberMeManager();
cookieRememberMeManager.setcookie(simplecookie);
return cookieRememberMeManager;
}
public ShiroRealm getShiroRealm(){
return new ShiroRealm();
}
@Bean
public SecurityManager getSecurityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(getShiroRealm());
securityManager.setRememberMeManager(getcookieRememberMeManager());//3
return securityManager;
}
//配置ShiroDialect 用来没有权限不显示页面
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
//shiro过滤器配置
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//未认证访问页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//认证成功跳转页面(一般不设置,默认登录成功跳转当前页面)
//shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权访问页面
shiroFilterFactoryBean.setUnauthorizedUrl("/refuse");
//通过map配置访问流程(顺序很重要)
linkedHashMap map = new linkedHashMap<>();
//配置静态资源
map.put("/js/**","anon");
map.put("/css/**","anon");
map.put("/jquery/**","anon");
map.put("/layui/**","anon");
//配置login页面
map.put("/login","anon");
//配置logout退出
map.put("/logout","logout");
//配置授权
map.put("/delete","perms[user:delete]"); //2
map.put("/select","perms[user:select]"); //2
//user设置记住我(二次登录不做认证操作)
map.put("/index","user");
map.put("/**","authc");//该路径认证后才能访问
//map.put("/**","anon");//所有路径都可以匿名访问
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
}
十四 连接数据库
授权AuthorizationInfo
通过SimpleAuthorizationInfo 进行授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String usercode = (String) principals.getPrimaryPrincipal();
Set permissions = new HashSet<>();
SimpleAuthorizationInfo authorizationInfo =
new SimpleAuthorizationInfo();
List allPermissions = userService.findAllPermissions(usercode);
for (int i = 0; i < allPermissions.size(); i++) {
permissions.add(allPermissions.get(i).getPercode());
}
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
SQL 语句
SELECT su.usercode,sr.name,sp.percode
from sys_user su
INNER JOIN sys_role sr
ON su.id=sr.available
INNER JOIN sys_role_permission srp
on sr.id=srp.sys_role_id
INNER JOIN sys_permission sp
ON srp.sys_permission_id =sp.id
where su.usercode='lisi'
多表内连接
内连接,外连接实际上都是在笛卡尔积(join)的基础上对记录进行筛选。
等值连接和非等值连接:这两者同时包含在内连接和外连接中,因为内连接和外连接都是需要连接条件的,条件为=则为等值连接,反之为非等值连接。
自然连接:等值连接的一种,使用natural join后面可以不使用on接查询条件,默认会将关联表中的相同字段进行比较,查询出的结果相同的字段会去重(值必须相等)。
内连接:使用inner join和join连接都行,重点是要有查询条件,条件使用on或者where引导查询都行,查询出的结果为两表都匹配的记录。
1.找不到secumaanger 因为ShiroFilterFactoryBean没配置securitymanager



