記事ディレクトリ
最初に必ずお読みください:
hiro フレームワークを学ぶのは難しくありませんが、基礎となるカプセル化は非常に奥深く、ブログで説明することはできません。これについては、おそらくさらにいくつかの記事が必要になるでしょう。この記事は主に hiro のプロジェクト構造の設定と基本的なものについてです。シロの機能です。このブログで構築したプロジェクトをベースに、これからシロを少し勉強しようと思ったら、理解するか使いこなせるか、手でコードを書く必要があります。キーボードを打つのは苦手ですが、給料は1万元未満です。後ほど更新していきますので、全部読んで確実にシロが身につくとは保証できませんが、必ず得るものはあると思います。
に固執します!
1. 開発環境
名前 | バージョン |
---|---|
その考えはわかります | 2019.3.5 x64 |
JDK | 1.8 |
MySQL | mysql-5.7.31-winx64 |
スプリングブーツ | 2.0以上 |
メイビン | apache-maven-3.6.3 |
しろ | 1.4.0 |
マイバティス | 2.1.0 |
2. プロジェクトの構築
1. SpringBoot プロジェクトを作成し、関連する pom 依存関係をインポートします。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/><!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. リソース内に application.yml 構成ファイルを作成します。
詳細な設定は次のとおりです:
アイデアが古いバージョンの場合、システムが MyBatis のマッパー ディレクトリを見つけることができないため、エラーが報告される場合があります。リソース ディレクトリにマッパー フォルダーを作成するか、一時的に MyBatis を無効にすることができます。 yml 設定ファイル内の関連設定 (コメントアウトの意味は、設定ファイル内のコメントに # 記号が使用されることです)。
server:
port: 8080
spring:
application:
name: shiro-springboot
datasource:
url: jdbc:mysql://localhost:3306/hibernate
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.xa.DruidXADataSource
thymeleaf:
cache: false
mvc:
static-path-pattern: /templates/user/**
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.zkr.mingyu.entity
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
level:
com.example.demo.dao : debug
SpringBoot でホット デプロイメントを有効にする方法は次のとおりです。私の他のブログの紹介を参照してください。
航空チケット: SpringBoot プロジェクトのホット デプロイメントを有効にする方法
3. SpringBoot スターター Application.class:
スタートアップ クラスのソース コードを作成します。
package com.zkr.mingyu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
プロジェクトが正常に開始できるかどうかをテストするには、localhost:8080 ポートにアクセスして、プロジェクトが正常に実行されるかどうかを確認します。
3. hiro構成クラスを構成する
現在のプロジェクト ディレクトリ:
SpringBoot と統合するための構成クラスを作成します。
設定クラスの詳細は以下のとおりです。
下から順に説明します。
ページ内で hiro タグが使用されていない場合は、Shiro と Thymeleaf の統合設定クラスを記述する必要はありません。
- カスタムレルム。
- セキュリティマネージャー DefaultWebSecuityManager を作成します。
- CreateShiroFilterFactoryBean
- hiro は、構成クラスを Thymeleaf と統合します。ページが hiro タグをサポートするため)。
この記事全体の中で最も重要かつ重要な 2 つのポイントは、Realm および hiro 構成クラスのカスタマイズです。全文コア
1. Realm クラスをカスタマイズします。
(1) MyRealm クラスを作成し、継承する必要がある AuthorizingRealm クラスを継承します。
(2) doGetAuthorizationInfo メソッドと doGetAuthenticationInfo メソッドを実装します。
ログインを実現するには、doGetAuthenticationInfo が核となり、doGetAuthenticationInfo() メソッドでアカウントのパスワードが検証されます。
ページのリソース制限、ユーザーがアクセスできるリソース、実行できる操作などの承認操作は doGetAuthorizationInfo() メソッドで実行されます。すべてこの方法で設定されます。
package com.zkr.mingyu.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.io.Serializable;
public class MyRealm extends AuthorizingRealm implements Serializable {
/**
* 授权
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权方法: doGetAuthorizationInfo");
return null;
}
/**
* 认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证方法: doGetAuthenticationInfo");
return null;
}
}
2. hiro 構成クラスを作成します。
この設定クラスは非常に重要なので、よく読んでリンクごとにリンクしてください。その後のパスワード暗号化(MD5 + ソルト + ハッシュ)はこのクラスで設定され、Thymeleaf などとの統合設定も行われます。
package com.zkr.mingyu.config;
import com.zkr.mingyu.shiro.MyRealm;
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;
/**标注 @Configuration 注解,
* 标注这是一个配置类,
* 让项目启动时加载该配置类。
*/
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactory
* 设置权限规则 需要注入securityManage
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
/**
* 创建安全管理器,
* 并为 securityManager 注入自定义的 Realm 类
* @param realm
* @return
*/
@Bean
public DefaultWebSecurityManager getSecurityManager(MyRealm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
/**
* 配置自定义 Realm 类
* @Bean 将 MyRealm 注入到 Spring 容器当中
* @return
*/
@Bean
public MyRealm getMyRealm(){
return new MyRealm();
}
}
4. ページ、コントローラー、サービスなどを作成します。
1. HTML ページを保存するためのテンプレート フォルダーをリソース ディレクトリに作成します。そしてインデックスページとログインページを作成します。
インデックス:
ログイン:
2. コントローラー、サービス、dao など
現在のディレクトリ構造:
コントローラー:
package com.zkr.mingyu.controller;
import com.zkr.mingyu.entity.User;
import com.zkr.mingyu.service.UserService;
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.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
@Controller
public class UserController {
@Resource
private UserService userService;
@RequestMapping("/index")
public String login(User user, Model model) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
try {
subject.login(token);
return "index";
} catch (UnknownAccountException e) {
model.addAttribute("msg", "用户名错误!");
return "login";
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg", "密码错误!");
return "login";
}
}
@RequestMapping("/login")
public String index() {
return "login";
}
@RequestMapping("/loginOut")
public String loginOut() {
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
@RequestMapping("/update")
public String update() {
return "/user/update";
}
}
サービス:
package com.zkr.mingyu.service;
import com.zkr.mingyu.entity.User;
import org.apache.ibatis.annotations.Param;
public interface UserService {
/**
* 根据用户名查找用户
* @param userName
* @return
*/
User findByUserName(@Param("username") String userName);
}
サービスの実装:
package com.zkr.mingyu.service;
import com.zkr.mingyu.dao.UserMapper;
import com.zkr.mingyu.entity.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
@Transactional //开启事务
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Override
public User findByUserName(String userName) {
return userMapper.findByUserName(userName);
}
}
ダオ:
package com.zkr.mingyu.dao;
import com.zkr.mingyu.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface UserMapper {
/**
* 根据用户名查找用户
* @param userName
* @return
*/
User findByUserName(@Param("username") String userName);
}
実在物:
package com.zkr.mingyu.entity;
import java.io.Serializable;
public class User implements Serializable {
/**
* id
*/
private Integer id;
/**
* 账号
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 权限
*/
private String auth;
/**
* 随机盐
*/
private String salt;
public User() {
}
public User(Integer id, String username, String password, String auth, String salt) {
this.id = id;
this.username = username;
this.password = password;
this.auth = auth;
this.salt = salt;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAuth() {
return auth;
}
public void setAuth(String auth) {
this.auth = auth;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", auth='" + auth + '\'' +
", salt='" + salt + '\'' +
'}';
}
}
マッパー:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zkr.mingyu.dao.UserMapper">
<select id="findByUserName" parameterType="String" resultType="user">
select id, username, password from user where username = #{username}
</select>
</mapper>
5. カスタマイズされた MyRealm を変更します
カスタマイズされた MyRealm クラスの doGetAuthenticationInfo() メソッドは、主にユーザー認証を構成します。
doGetAuthorizationInfo() メソッドは主にユーザー権限の設定を行いますが、端的に言えば、このユーザーにどのような役割と権限が割り当てられているかを意味します。また、特定のリソースにアクセスできるかどうか、アクセスできる場合、ユーザーがそのリソースに対してどのような操作を実行できるか。操作 == CRUD。
package com.zkr.mingyu.shiro;
import com.zkr.mingyu.entity.User;
import com.zkr.mingyu.service.UserService;
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.springframework.beans.factory.annotation.Autowired;
import java.io.Serializable;
public class MyRealm extends AuthorizingRealm implements Serializable {
@Autowired
private UserService userService;
/**
* 执行授权逻辑
* 权限要和资源对应
* 权限声明该用户可以访问系统中哪些资源,对系统中哪些资源进行操作
* 不同的用户,拥有不同的权限
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权方法: doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
User byUserName = userService.findByUserName(user.getUsername());
/**
* 这个方法中为授权操作
* 基本常用方法有:
*/
/**
* 控制台打印结果:
* getRoles: null
* getObjectPermissions: null
* getStringPermissions: [user:add]
* getClass: class org.apache.shiro.authz.SimpleAuthorizationInfo
*/
//获取用户角色
/* System.out.println("getRoles: " + info.getRoles());
System.out.println("getObjectPermissions: " + info.getObjectPermissions());
//获取用户权限
System.out.println("getStringPermissions: " + info.getStringPermissions());
System.out.println("getClass: " + info.getClass());*/
return null;
}
/**
* 认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证方法: doGetAuthenticationInfo");
String username = (String) token.getPrincipal();
User user = userService.findByUserName(username);
if(user == null){
return null;
}
return new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
}
}
これは私が作成したもう 1 つの MyRealm 構成です。見て理解してください。後日更新します このブログの冒頭でも述べたように、プロジェクトの基本的な枠組みを構築することです。後で記事の最後に新しいブログのリンクを追加します。最近お時間がありましたら、この知識を共有していただきありがとうございます。
6. リソースのアクセス権限を設定するShiroConfig
ShiroFilterFactoryBean メソッドは主に、特定のリソースにアクセスするために必要な権限を構成します。そしてデフォルトのログインページのURLアドレスを設定します。権限が不十分な特定のリソースにアクセスした場合に、どのページにジャンプするかをここで設定します。
DefaultWebSecurityManager はセキュリティ マネージャーです。後でパスワード暗号化操作 (パスワード + ソルト + MD5 + ハッシュ) を実行するときは、DefaultWebSecurityManager() メソッドでカスタム パスワード マネージャーを構成する必要があります。
package com.zkr.mingyu.config;
import com.zkr.mingyu.shiro.MyRealm;
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.LinkedHashMap;
import java.util.Map;
/**标注 @Configuration 注解,
* 标注这是一个配置类,
* 让项目启动时加载该配置类。
*/
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactory
* 设置权限规则 需要注入securityManage
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/**
* Shiro内置过滤器,可实现权限相关的拦截器
* 常用的过滤器:
* anon: 无需认证(登录) 可以访问
* authc: 必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms: 该资源必须得到资源权限才可以访问
* role: 该资源必须得到角色权限才可以访问
*/
Map<String, String> filterMap = new LinkedHashMap<String,String>();
filterMap.put("/login","anon");
filterMap.put("/index","anon");
filterMap.put("/*","authc");
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建安全管理器,
* 并为 securityManager 注入自定义的 Realm 类
* @param realm
* @return
*/
@Bean
public DefaultWebSecurityManager getSecurityManager(MyRealm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
/**
* 配置自定义 Realm 类
* @Bean 将 MyRealm 注入到 Spring 容器当中
* @return
*/
@Bean
public MyRealm getMyRealm(){
return new MyRealm();
}
}
コードはそれほど多くなく、デモを書いて後で少しずつ改良していくだけなので、時間があるときに新しい記事を更新していきます。たとえば、パスワード暗号化、リソース権限のセグメント化、セッション、キャッシュなどです。
後で新しい関数を書いたら、記事の最初と最後に配置し、リンクを貼り付けます。読んだらいいねをお願いします♪ いいねが更新の励みになります!記事を収集すると、後ほど記事の先頭に新しいブログへのリンクが表示されます。
添付の文章は(お互いを励ますため):
沸騰したお湯の中では反射は見えず、怒りでは真実が見えません。