apache shiro例子
闲来无事看到之前写的shiro例子,传上来,
之前在一家公司接触过一个项目用到了shiro,不过那个项目是公司买来的,前后端封装的比较厉害,用着不是并那么方便,简单学习shiro后,写了个小demo。
shiro相比spring的安全框架上手要友好的多。
这是基本结构。
我使用的是spring boot ,这样方便配置,简单的写了个登陆过程。采用spring的thymeleaf。spring data jpa读取数据库中用户信息作权限判断
启动类就不贴了,会spring boot的都没问题
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.zhengyj</groupId>
<artifactId>springboot-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-shiro</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8081
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_shiro?useUnicode=true&characterEncoding=UTF-8&useSSL=true
username: root
password: root123
type: com.alibaba.druid.pool.DruidDataSource
jpa:
show-sql: true
hibernate:
ddl-auto: update
http:
encoding:
charset: utf-8
enabled: true
thymeleaf:
prefix: classpath:/templates/
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="/loginsave">
用户名:<input name="name" type="text"/><br>
密码:<input name="password" type="text"/><br>
<input type="submit" value="登录系统"/>
</form>
<p th:text="${hello}"></p>
</body>
</html>
controller
package org.zhengyj.springbootshiro.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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.zhengyj.springbootshiro.entity.User;
import org.zhengyj.springbootshiro.service.LoginService;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
/**
*
* @Author zhengyj
* @Description :登录控制层
* @Date 2019/4/17
**/
@Controller
public class LoginController {
/**
* 首页
* @return
*/
@RequestMapping(value = "/index")
public String index(){
return "index";
}
/**
* 登录
* @return
*/
@RequestMapping(value = "/login")
public String login(){
return "login";
}
/**
* 此处做权限跳转处理,返回不同页面
*/
@RequestMapping(value = "/loginsave")
public String loginSave(User user){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getName(),user.getPassword());
try{
subject.login(token);
//这个index页面就是随便写点什么标注下就行
return "index";
}catch(UnknownAccountException e){
return "login";
}catch(IncorrectCredentialsException i){
return "login";
}
}
}
User类(这个可以用lombok,有点懒了)
package org.zhengyj.springbootshiro.entity;
import javax.persistence.*;
import java.util.List;
/**
*
* @Author zhengyingjun
* @Description :shiro 用户类
* @Date 2019/4/17
**/
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(unique = true)
private String name;
private String password;
@OneToMany(cascade = CascadeType.ALL,mappedBy = "user")
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Role
package org.zhengyj.springbootshiro.entity;
import javax.persistence.*;
import java.util.List;
/**
*
* @Author zhengyingjun
* @Description :shiro 角色类
* @Date 2019/4/17
**/
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String roleName;
@ManyToOne(fetch = FetchType.EAGER)
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Permission> getPermissions() {
return permissions;
}
public void setPermissions(List<Permission> permissions) {
this.permissions = permissions;
}
@OneToMany(cascade = CascadeType.ALL,mappedBy = "role")
private List<Permission> permissions;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
}
Permission
package org.zhengyj.springbootshiro.entity;
import javax.persistence.*;
/**
*
* @Author zhengyingjun
* @Description : shiro 权限类
* @Date 2019/4/17
**/
@Entity
public class Permission {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String permission;
@ManyToOne(fetch = FetchType.EAGER)
private Role role;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
RoleRepository(使用的Spring Data JPA)
package org.zhengyj.springbootshiro.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.zhengyj.springbootshiro.entity.Role;
/**
*
* @Author zhengyingjun
* @Description :角色
* @Date 2019/4/17
**/
public interface RoleRepository extends JpaRepository<Role,Long> {
}
UserRepository
package org.zhengyj.springbootshiro.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.zhengyj.springbootshiro.entity.User;
/**
*
* @Author zhengyingjun
* @Description :用户
* @Date 2019/4/17
**/
public interface UserRepository extends JpaRepository<User,Long> {
/**
*自定义查询
* @param name
* @return
*/
User findByName(String name);
}
service接口(有些好像是没用上)
package org.zhengyj.springbootshiro.service;
import org.zhengyj.springbootshiro.entity.Role;
import org.zhengyj.springbootshiro.entity.User;
/**
*
* @Author zhengyingjun
* @Description :业务
* @Date 2019/4/17
**/
public interface LoginService {
User addUser(User user);
Role addRole(User user,String rolename);
User findByName(String name);
}
service实现类
package org.zhengyj.springbootshiro.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zhengyj.springbootshiro.entity.Permission;
import org.zhengyj.springbootshiro.entity.Role;
import org.zhengyj.springbootshiro.entity.User;
import org.zhengyj.springbootshiro.repository.RoleRepository;
import org.zhengyj.springbootshiro.repository.UserRepository;
import org.zhengyj.springbootshiro.service.LoginService;
import java.util.ArrayList;
import java.util.List;
/**
*
* @Author zhengyingjun
* @Description :具体实现
* @Date 2019/4/17
**/
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Override
public User addUser(User user) {
return userRepository.save(user);
}
@Override
public Role addRole(User user,String rolename) {
Role role = new Role();
role.setRoleName(rolename);
role.setUser(user);
Permission permission1 = new Permission();
permission1.setPermission("create");
permission1.setRole(role);
Permission permission2 = new Permission();
permission2.setPermission("update");
permission2.setRole(role);
List<Permission> list = new ArrayList<>();
list.add(permission1);
list.add(permission2);
//放入role统一保存
role.setPermissions(list);
roleRepository.save(role);
return role;
}
@Override
public User findByName(String name) {
return userRepository.findByName(name);
}
}
接下来就是最重要的配置了
这个简要说明下,用到哪个页面就配置哪个
package org.zhengyj.springbootshiro.config;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
*
* @Author zhengyingjun
* @Description :shiro 过滤配置
* @Date 2019/4/17
**/
@Configuration
public class ShiroConfiguration {
/**
* 加入注解
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean(name = "myShiroRealm")
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
/**
* 权限管理
* @return
*/
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map = new HashMap<>();
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index");
//报错页
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
//退出
map.put("/logout","logout");
map.put("/login","anon");
map.put("/loginsave","anon");
//对所有用户认证
map.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
}
认证与校验
package org.zhengyj.springbootshiro.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.springframework.beans.factory.annotation.Autowired;
import org.zhengyj.springbootshiro.entity.Permission;
import org.zhengyj.springbootshiro.entity.Role;
import org.zhengyj.springbootshiro.entity.User;
import org.zhengyj.springbootshiro.service.LoginService;
@Slf4j
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private LoginService service;
/**
* 添加权限
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
log.info("授权");
User user = (User) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (Role role : user.getRoles()) {
//添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
//添加权限
for (Permission permission : role.getPermissions()) {
simpleAuthorizationInfo.addStringPermission(permission.getPermission());
}
}
return simpleAuthorizationInfo;
}
/**
* 认证
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
log.info("认证");
//??先进行认证?
if (authenticationToken.getPrincipal() == null) {
return null;
}
String name = (String)authenticationToken.getPrincipal();
User user = service.findByName(name);
//空值校验
if (user == null) {
return null;
} else {
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getName(), user.getPassword(), getName());
return simpleAuthenticationInfo;
}
}
}