本人也是第一次刚搭建shiro框架,参考一些资料和博客,进行搭建,有啥不足之处或改进的地方希望各位指出。
先建好springboot项目,进行测试
第一步,引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--没有此依赖shiro注解权限会失效-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--lombok插件使用依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mybatis plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatisplus-spring-boot-starter</artifactId>
<version>${mybatisplus-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<!--数据源相关-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--shiro依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro-spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
第二部,配置application.properties文件
server.port=8080
# 数据库访问配置
# 主数据源,默认的
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shrio?Unicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#集成Freemark
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.allow-session-override=true
#Mybatis配置
mybatis-plus.mapper-locations=classpath:mappers/*.xml
#mybatis-plus的model包
mybatis-plus.typeAliasesPackage=com.joecy.entity
#global-config:
#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
#id-type: 2
mybatis-plus.global-config.id-type=0
#驼峰式命名映射
mybatis-plus.global-config.db-column-underline=true
第三步,项目Action启动类权限访问和拦截器
@GetMapping(value = "/login")
public String login(){
return "login";
}
@PostMapping(value = "/user_login")
public String login(@RequestParam String username, @RequestParam String password, Model model){
try {
System.out.println(username+" "+password);
model.addAttribute("username", username);
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
//完成登录
subject.login(usernamePasswordToken);
return "redirect:/index";
} catch (Exception e) {
String ex = e.getClass().getName();
if (ex != null) {
if (UnknownAccountException.class.getName().equals(ex)) {
System.out.println("用户名不存在");
} else if (IncorrectCredentialsException.class.getName().equals(ex)) {
System.out.println("账户或密码错误");
} else {
System.out.println("未知错误");
}
}
//返回登录页面
return "login";
}
}
@ResponseBody
@GetMapping(value = "/index")
public String index(){
return "welcome";
}
//注解的使用
//管理员角色
@ResponseBody
@RequiresRoles("admin")
@RequestMapping(value = "/role/admin")
public String roleAdmin(){
return "I am admin";
}
//只拥有添加权限
@ResponseBody
@RequiresPermissions("add")
@RequestMapping(value = "/permission/add")
public String Permission(){
return "I have permission add";
}
第四步,建立实体类,我只列出一个,剩下看自己需求建立
@Data
public class SecRole extends Model<SecRole> {
@TableId
private Integer id;
private String name;
@TableField(exist = false)
private List<SecPermission> permissions;
@Override
protected Serializable pkVal() {
return this.id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<SecPermission> getPermissions() {
return permissions;
}
public void setPermissions(List<SecPermission> permissions) {
this.permissions = permissions;
}
}
第五步,建立MyShiroRealm和ShiroConfig2个类
public class MyShiroRealm extends AuthorizingRealm {
//角色权限和对应权限添加
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
System.out.println(principalCollection.getPrimaryPrincipal());
SecUser user= (SecUser) principalCollection.getPrimaryPrincipal();
//保存所有角色名
Set<String> allRoles = new HashSet<>();
System.out.println("当前角色所有名字 :"+allRoles.size());
//保存所有权限名
Set<String> allPermissions = new HashSet<>();
System.out.println("当前权限所有名字 :"+allRoles.size());
//查询对应角色
List<SecUserRole> secUserRoles = new SecUserRole().selectList(new EntityWrapper().eq("user_id", user.getId()));
for (SecUserRole userRole:secUserRoles) {
SecRole role = new SecRole();
role.setId(userRole.getRoleId());
role = role.selectById();
allRoles.add(role.getName());
//查询所有权限
List<SecPermission> permissions = new ArrayList<>();
List<SecRolePermission> rolePermissions = new SecRolePermission().selectList(new EntityWrapper().eq("role_id", role.getId()));
for (SecRolePermission rolePermission:rolePermissions) {
SecPermission permission = new SecPermission();
permission.setId(rolePermission.getPermissionId());
permission = permission.selectById();
System.out.println(permission.getName());
allPermissions.add(permission.getName());
}
}
//添加角色
simpleAuthorizationInfo.addRoles(allRoles);
simpleAuthorizationInfo.addStringPermissions(allPermissions);
user.getRoles();
System.out.println(user+" "+allRoles);
return simpleAuthorizationInfo;
}
//用户认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 1、登录认证的方法需要先执行,需要用他来判断登录的用户信息是否合法
String username = (String) token.getPrincipal(); // 取得用户名
// 需要通过用户名取得用户的完整信息,利用业务层操作
System.out.println("当前角色名字 :"+username);
SecUser user = null;
try {
user = new SecUser().selectOne(new EntityWrapper().eq("username",username));
} catch (Exception e) {
e.printStackTrace();
}
if (user == null) {
throw new UnknownAccountException("该用户名称不存在!");
} else { // 进行密码的验证处理
String password =new String((char[]) token.getCredentials());
// 将数据库中的密码与输入的密码进行比较,这样就可以确定当前用户是否可以正常登录
if (user.getPassword().equals(password)) { // 密码正确
AuthenticationInfo auth = new SimpleAuthenticationInfo(user, password, "memberRealm");
return auth;
} else {
throw new IncorrectCredentialsException("密码错误!");
}
}
}
}
@Configuration
public class ShiroConfig {
//将自己的验证方式加入容器
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
System.out.println("登录-------------跳转");
shiroFilterFactoryBean.setSuccessUrl("/index");
// 权限控制map.
LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
filterChainDefinitionMap.put("/css/**", "anon"); //表示可以匿名访问
filterChainDefinitionMap.put("/js/**", "anon"); //表示可以匿名访问
filterChainDefinitionMap.put("/img/**", "anon"); //表示可以匿名访问
filterChainDefinitionMap.put("/font/**", "anon"); //表示可以匿名访问
filterChainDefinitionMap.put("/images/**", "anon"); //表示可以匿名访问
filterChainDefinitionMap.put("/login", "anon"); //表示可以匿名访问
filterChainDefinitionMap.put("/user_login", "anon");
filterChainDefinitionMap.put("/logout*","logout");
filterChainDefinitionMap.put("/error","anon");
filterChainDefinitionMap.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
//加入注解的使用,不加入这个注解不生效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
System.out.println("开启了shiro注解功能");
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
mapper中代码如下
@Mapper
public interface SecRoleMapper extends BaseMapper<SecRole> {
}
和实体类一样,之列了一个,剩下自己补齐。
最后写个登陆测试界面调到user_login方法进行测试就行了。我的表结构如下:
注意,name的值 记得@Requires注解里的值一样咯。