java|SpringBoot新闻管理系统——shiro+SpringCloud微服务

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表并填入如下内容
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

对应的,有三种角色,负责不同的权限范围
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

在user中创建三个管理员角色
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

在user_roles表中指定用户的角色
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

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:容错管理组件
下面写一个Eureka组件的项目
2.1 项目新建 新建项目
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

添加依赖如下:
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

新建一个文件夹,取该模块名字为provider
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

在项目中导入依赖包
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

2.2 构建项目骨架 java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

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;

配置与实体类对应的数据库:
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

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 编写消费者 由于可以用其他服务来查询信息,可以省去对数据库的操作
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

直接在项目中就可以查询到用户信息
@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; } }

接下来写注册中心。注册中心定期更新服务列表,客户消费者定期拉取注册中心中已经注册的服务。
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

配置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); }}

可以进入注册中心管理界面
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

可以看到注册到的服务
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

接下来把刚刚创建的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已经被注册进去了。
java|SpringBoot新闻管理系统——shiro+SpringCloud微服务
文章图片

    推荐阅读