1.shiro 核心api
Subject : 用户主体,把操作交给SecurityManger
SecurityManger : 安全管理器 ,关联Realm
Realm : Shiro 连接数据的桥梁
2.引入依赖包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
3.创建UserRealm类
import com.dntest.springbootshiro.user.model.Module;
import com.dntest.springbootshiro.user.model.Role;
import com.dntest.springbootshiro.user.model.User;
import com.dntest.springbootshiro.user.service.UserService;
import org.apache.shiro.SecurityUtils;
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.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @version V1.0
* @author: MR.DN
* @ClassName: UserRealm
* @Date: 2019/3/18 15:49
* @Description: TODO
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
/**
* 执行授权逻辑
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Subject subject = SecurityUtils.getSubject();
User user = (User)subject.getPrincipal();
Set<Role> roles = user.getRoles();
for(Role role : roles){
//授权账户角色
info.addRole(role.getRname());
Set<Module> modules = role.getModules();
for(Module module : modules){
//授权账户权限
info.addStringPermission(module.getMname());
}
}
return info;
}
/**
* 执行认证逻辑
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
String username = token.getUsername();
User user = userService.findByUsername(username);
if(user==null){
return null;
}
return new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getName());
}
}
4.编写shiro配置类ShiroConfig
@Configuration
public class ShiroConfig {
/**
* 1.注入shiro过滤器工厂 ShiroFilterFactoryBean
* 2.注入自定义realm userRealm
* 3.注入安全管理器 DefaultWebSecurityManager
* 4.密码加密比较器 CredentialsMatcher
* 5.生命周期 LifecycleBeanPostProcessor
*/
}
加 注解@ Configuration
- 1.常用过滤器
shiro 内置过滤器 实现相关拦截
常用拦截器
anon 无需认证
authc 必须认证
user 如果使用rememberMe 的功能可以直接使用
perms 该资源必须得到资源权限才可以访问
role 该资源必须得到角色权限才可访问
- 2.创建DefaultWebSecurityManger
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManger(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManger = new DefaultWebSecurityManager();
//关联Realm
securityManger.setRealm(userRealm);
return securityManger;
}
- 3.创建Realm
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
- 4.创建ShiroFilterFactoryBean
注意顺序,anon 在最前面,authc在最后
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(securityManager);
bean.setLoginUrl("/tologin");
bean.setUnauthorizedUrl("/unAuth");
LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
//表示可以匿名访问
filterChainDefinitionMap.put("/tologin", "anon");
filterChainDefinitionMap.put("/login", "anon");
//表示必须认证才能访问访问
filterChainDefinitionMap.put("/**", "authc");
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return bean;
}
- 5.配置自定义的密码比较器
//配置自定义的密码比较器
@Bean(name="credentialsMatcher")
public CredentialsMatcher credentialsMatcher() {
return new CredentialsMatcher();
}
//新建一个类
public class CredentialsMatcher extends SimpleCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String inPassword = new String(upToken.getPassword());
String password = (String) info.getCredentials();
return this.equals(inPassword,password);
}
}
- 6.配置生命周期
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(manager);
return advisor;
}
5.整合mybatis
- 引入依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.11</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
- 配置文件
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/img?characterEncoding=UTF-8
spring.datasource.username=test
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
- 创建表
- 建表语句
CREATE TABLE `user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
CREATE TABLE `role` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`rname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
CREATE TABLE `module` (
`mid` int(11) NOT NULL AUTO_INCREMENT,
`mname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`mid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
CREATE TABLE `user_role` (
`uid` int(11) DEFAULT NULL,
`rid` int(11) DEFAULT NULL,
KEY `u_fk` (`uid`),
KEY `r_fk` (`rid`),
CONSTRAINT `r_fk` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`),
CONSTRAINT `u_fk` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `module_role` (
`rid` int(11) DEFAULT NULL,
`mid` int(11) DEFAULT NULL,
KEY `rid` (`rid`),
KEY `mid` (`mid`),
CONSTRAINT `mid` FOREIGN KEY (`mid`) REFERENCES `module` (`mid`),
CONSTRAINT `rid` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
2.对应model
public class User {
private Integer uid;
private String username;
private String password;
private Set<Role> roles = new HashSet<>();
.....
}
public class Role {
private Integer rid;
private String rname;
private Set<Role> roles = new HashSet<>();
private Set<Module> modules = new HashSet<>();
......
}
public class Module {
private Integer mid;
private String mname;
private Set<Module> modules = new HashSet<>();
......
}
-
编写xml
1.结果集,用户,角色,权限的多对多
<resultMap id="BaseResultMap" type="com.dntest.springbootshiro.user.model.User" >
<id column="uid" property="uid" jdbcType="INTEGER" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<collection property="roles" ofType="com.dntest.springbootshiro.user.model.Role">
<id column="rid" property="rid" jdbcType="INTEGER" />
<result column="rname" property="rname" jdbcType="VARCHAR" />
<collection property="modules" ofType="com.dntest.springbootshiro.user.model.Module">
<id column="mid" property="mid" jdbcType="INTEGER" />
<result column="mname" property="mname" jdbcType="VARCHAR" />
</collection>
</collection>
</resultMap>
2.sql语句关联,多表查询,把用户对应的角色和权限全部查出来
<select id="findByUsername" resultMap="BaseResultMap" parameterType="java.lang.String" >
SELECT u.*,r.*,m.* FROM user u
left join user_role ur on ur.uid = u.uid
left join role r on r.rid = ur.rid
left join module_role mr on mr.rid = r.rid
left join module m on mr.mid = m.mid
WHERE username = #{username}
</select>
5.创建loginController类
@Controller
public class LoginController {
@GetMapping("tologin")
public String tologin(Model model){
model.addAttribute("wolcome","欢迎登陆");
return "login";
}
@RequestMapping("login")
public String login(String username,String password,Model model){
UsernamePasswordToken upToken = new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try{
subject.login(upToken);
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "login";
}
model.addAttribute("username",username);
return "index";
}
@RequestMapping("/logOut")
public String logOut(HttpSession session) {
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "shiro/login";
}
}