1 shiro shiro是一个安全框架,其主要功能如下
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
1.1 数据库设计 根据管理功能划分为三个权限,创建permission表并填入如下内容
文章图片
对应的,有三种角色,负责不同的权限范围
文章图片
在user中创建三个管理员角色
文章图片
在user_roles表中指定用户的角色
文章图片
1.2 实体类编写 在编写实体类后就可以直接生成相应的数据库了:
Role
@Entity
@Table(name = "t_role")
public class Role implements Serializable {private static final long serialVersionUID = -460222871362844049L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
@ManyToMany(mappedBy = "roles")
private Set users=new HashSet<>(0);
@ManyToMany(fetch = FetchType.EAGER)
private Set permissions=new HashSet<>(0);
User
加上权限和角色:都用集合来存放
@ManyToMany(mappedBy = "roles")
private Set users=new HashSet<>(0);
@ManyToMany(fetch = FetchType.EAGER)
private Set permissions=new HashSet<>(0);
Permission:
按照数据库设计的来。
@Entity
@Table(name="t_permission")
public class Permission implements Serializable {private static final long serialVersionUID = 3210360881591198664L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String code;
private String description;
1.3 编写realm 如上所述,相当于dao层废弃掉之前的login方法。
将用户信息存放在token中,我们在验证登录时要将其从token中取出,然后进行验证。
public class NewsRealm extends AuthorizingRealm {
public void setName(String name){setName("newsRealm");
}@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken upToken=(UsernamePasswordToken)authenticationToken;
String username=upToken.getUsername();
String password=new String(upToken.getPassword());
User user=userService.checkUsers(username,password);
if(user!=null){
return new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
}
return null;
}@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取认证的用户数据
User user=(User)principalCollection.getPrimaryPrincipal();
//构造认证数据
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
Set roles=user.getRoles();
for(Role role:roles){
//添加角色信息
info.addRole(role.getName());
for(Permission permission: role.getPermissions()){
info.addStringPermission(permission.getCode());
}
}
return info;
}@Autowired
private UserService userService;
}
1.4 编写配置类 主要是告诉shiroRealm、过滤器所在的项目位置。
@Configuration
public class ShiroConfiguration {
//创建realm
@Bean
public NewsRealm getRealm(){return new NewsRealm();
}@Bean
public SecurityManager securityManager(NewsRealm realm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(realm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactory=new ShiroFilterFactoryBean();
shiroFilterFactory.setSecurityManager(securityManager);
//通用配置
shiroFilterFactory.setLoginUrl("/admin");
shiroFilterFactory.setUnauthorizedUrl("/admin");
Map,String> filterMap=new LinkedHashMap<>();
filterMap.put("/admin/login","anon");
filterMap.put("/admin/**","authc");
shiroFilterFactory.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactory;
}
//开启注解支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
1.5 在web层调用登录服务。
public class LoginController {
@Autowired
private UserService userService;
@GetMapping
public String loginPage(){
return "admin/login";
}@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password,
HttpSession session, RedirectAttributes attributes){try{
//构建用户令牌
UsernamePasswordToken uptoken=new UsernamePasswordToken(username,password);
//获取subject
Subject subject= SecurityUtils.getSubject();
subject.login(uptoken);
User user=(User) subject.getPrincipal();
session.setAttribute("user",user);
return "admin/index";
}catch (Exception e){
attributes.addFlashAttribute("message","用户名或密码错误");
return "redirect:/admin";
}
}@GetMapping("/logout")
public String logout(HttpSession session){
session.removeAttribute("user");
return "redirect:/admin";
}
2 微服务 SpringCloud 【java|SpringBoot新闻管理系统——shiro+SpringCloud微服务】特点有:单一职责、高度自治。
组件有:
- Eureka:服务治理组件,包含了服务注册中心,服务注册于发现机制的实现
- Zuul:网关组件
- Ribbon:负载均衡
- Feign:服务调用
- Hystrix:容错管理组件
2.1 项目新建 新建项目
文章图片
文章图片
添加依赖如下:
文章图片
新建一个文件夹,取该模块名字为provider
文章图片
在项目中导入依赖包
文章图片
2.2 构建项目骨架
文章图片
2.3 编写实体类
@Table(name = "tb_user")
public class User implements Serializable {
private static final long serialVersionUID = 4374725483383661051L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String name;
private Integer age;
private Integer sex;
private Date birthday;
private Date created;
private Date updated;
配置与实体类对应的数据库:
文章图片
2.4 编写服务层和web层 service:
@Service
public class UserService {
@Autowired(required = false)
private UserMapper userMapper;
public User queryById(Long id){
return this.userMapper.selectByPrimaryKey(id);
}
}
controller:
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("{id}")
public User queryById(@PathVariable("id") Long id){
return this.userService.queryById(id);
}
}
运行之后可以从数据库中查询到用户信息。
2.5 编写消费者 由于可以用其他服务来查询信息,可以省去对数据库的操作
文章图片
直接在项目中就可以查询到用户信息
@Controller
@RequestMapping("consumer/user")
public class UserController {
@Autowired
private RestTemplate restTemplate;
@GetMapping
@ResponseBody
public User queryById(@RequestParam("id") Long id){
User user = this.restTemplate.getForObject("http://localhost:8081/user/"+id,User.class);
return user;
}
}
接下来写注册中心。注册中心定期更新服务列表,客户消费者定期拉取注册中心中已经注册的服务。
文章图片
配置application文件
server:
port: 10086
spring:
application:
name: eureka-server #应用名称,会在Eureka中显示
eureka:
client:
service-url: #eurekaserver的地址,现在是自己的地址,如果是集群,需要加上其他server地址
defaultZone: http://localhost:${server.port}/eureka
声明当前项目是一个注册中心
@SpringBootApplication
@EnableEurekaServer//声明当前springboot应用是一个eureka服务中心
public class EurekaApplication {public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}}
可以进入注册中心管理界面
文章图片
可以看到注册到的服务
文章图片
接下来把刚刚创建的provider也注册进服务:
server:
port: 8081spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db?serverTimezone=Asia/Shanghai
username: root
password: 123456
application:
name: service-provider
再次启动注册中心可以看到provider已经被注册进去了。
文章图片
推荐阅读
- #|【微服务】一文读懂网关概念+Nginx正反向代理+负载均衡+Spring Cloud Gateway(多栗子)
- MQ|kafka 文件存储 消息同步机制
- java|FPGA时序约束分享01_约束四大步骤
- java|SpringMVC-核心组件
- java|史上最强SpringMVC请求处理流程解析(通俗易懂)
- 技术交流|#SpringMvc 了解请求处理的流程,简化说明(图解)
- java|SpringMvc请求流程详解及核心组件(面试题)
- Spring|Spring MVC学习(3)—Spring MVC中的核心组件以及请求的执行流程
- python|他来了!性能吊打 Node.js 和 Deno 的新一代 javaScript 运行时!