SpringBoot整合shiro從初戀到失戀

建個項目或者模塊,目錄結構以下

在pom.xml中加入shiro依賴,其餘依賴自行添加(lombok,jpa,mybatis,web,thymeleaf等)

<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

application.properties中的配置

##端口號
server.port=8888
##數據庫配置
##數據庫地址
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8&useSSL=false\
  &serverTimezone=GMT%2B8
##數據庫用戶名
spring.datasource.username=root
##數據庫密碼
spring.datasource.password=Panbing936@
##數據庫驅動
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
##validate  加載hibernate時,驗證建立數據庫表結構
##create   每次加載hibernate,從新建立數據庫表結構,這就是致使數據庫表數據丟失的緣由。
##create-drop        加載hibernate時建立,退出是刪除表結構
##update                 加載hibernate自動更新數據庫結構
##validate 啓動時驗證表的結構,不會建立表
##none  啓動時不作任何操做
spring.jpa.hibernate.ddl-auto=update
##控制檯打印sql
spring.jpa.show-sql=true
# 建議在開發時關閉緩存,否則無法看到實時頁面
spring.thymeleaf.cache=false
##去除thymeleaf的html嚴格校驗
spring.thymeleaf.mode=LEGACYHTML5
#沒下面這行配置就會報這個錯誤
#Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect

實體類SysMenu.java中的代碼

@Entity
@Data
public class SysMenu implements Serializable {

    @Id
    @GeneratedValue
    private Integer menuId;
    private String menuName;

    @ManyToMany
    @JoinTable(name = "SysRoleMenu", joinColumns = {@JoinColumn(name = "menuId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
    private List<SysRole> roleList;
}

實體類SysRole.java中的代碼

@Entity
@Data
public class SysRole implements Serializable {

    @Id
    @GeneratedValue
    private Integer roleId;

    private String roleName;

    //多對多關係
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "SysRoleMenu", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "menuId")})
    private List<SysMenu> menuList;

    //多對多關係
    @ManyToMany
    @JoinTable(name = "SysUserRole", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "userId")})
    private List<SysUser> userList;// 一個角色對應多個用戶
}

實體類SysUser.java中的代碼

@Entity
@Data
public class SysUser implements Serializable {

    @Id
    @GeneratedValue
    private Integer userId;
    @NotEmpty
    private String userName;
    @NotEmpty
    private String passWord;

    //多對多關係
    @ManyToMany(fetch = FetchType.EAGER)
    //急加載,加載一個實體時,定義急加載的屬性會當即從數據庫中加載
    //FetchType.LAZY:懶加載,加載一個實體時,定義懶加載的屬性不會立刻從數據庫中加載
    @JoinTable(name = "SysUserRole", joinColumns = {@JoinColumn(name = "userId")},
            inverseJoinColumns = {@JoinColumn(name = "roleId")})
    private List<SysRole> roleList;// 一個用戶具備多個角色

}

接口UserRepository.java中的代碼

public interface UserRepository extends CrudRepository<SysUser,Long> {

    SysUser findByUserName(String username);
}

下面的代碼纔是shiro相關的

MyshiroRealm.java

public class MyShiroRealm extends AuthorizingRealm {

    @Resource
    private UserRepository userRepository;

    //受權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        SysUser userInfo  = (SysUser)principals.getPrimaryPrincipal();
        for(SysRole role:userInfo.getRoleList()){
            authorizationInfo.addRole(role.getRoleName());
            for(SysMenu menu:role.getMenuList()){
                authorizationInfo.addStringPermission(menu.getMenuName());
            }
        }
        return authorizationInfo;
    }

    //認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        //得到當前用戶的用戶名
        String username = (String)token.getPrincipal();
        System.out.println(token.getCredentials());
        //根據用戶名找到對象
        //實際項目中,這裏能夠根據實際狀況作緩存,若是不作,Shiro本身也是有時間間隔機制,2分鐘內不會重複執行該方法
        SysUser userInfo = userRepository.findByUserName(username);
        if(userInfo == null){
            return null;
        }
        //這裏會去校驗密碼是否正確
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                userInfo, //用戶名
                userInfo.getPassWord(),//密碼
                getName()
        );
        return authenticationInfo;
    }
}

ShiroConfig.java

@Configuration
public class ShiroConfig {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        logger.info("啓動shiroFilter--時間是:" + new Date());
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //shiro攔截器
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        //<!-- authc:全部url都必須認證經過才能夠訪問; anon:全部url都均可以匿名訪問-->
        //<!-- 過濾鏈定義,從上向下順序執行,通常將/**放在最爲下邊 -->

        // 配置不被攔截的資源及連接
        filterChainDefinitionMap.put("/static/**", "anon");
        // 退出過濾器
        filterChainDefinitionMap.put("/logout", "logout");

        //配置須要認證權限的
        filterChainDefinitionMap.put("/**", "authc");
        // 若是不設置默認會自動尋找Web工程根目錄下的"/login"頁面,即本文使用的login.html
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登陸成功後要跳轉的連接
        shiroFilterFactoryBean.setSuccessUrl("/index");

        //未受權界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    //自定義身份認證Realm(包含用戶名密碼校驗,權限校驗等)
    @Bean
    public MyShiroRealm myShiroRealm(){
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }


    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    //開啓shiro aop註解支持,不開啓的話權限驗證就會失效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    //配置異常處理,不配置的話沒有權限後臺報錯,前臺不會跳轉到403頁面
    @Bean(name="simpleMappingExceptionResolver")
    public SimpleMappingExceptionResolver
    createSimpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("DatabaseException", "databaseError");//數據庫異常處理
        mappings.setProperty("UnauthorizedException","403");
        simpleMappingExceptionResolver.setExceptionMappings(mappings);  // None by default
        simpleMappingExceptionResolver.setDefaultErrorView("error");    // No default
        simpleMappingExceptionResolver.setExceptionAttribute("ex");     // Default is "exception"
        return simpleMappingExceptionResolver;
    }
}

thymeleaf的頁面代碼

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
index
<br/>
<form th:action="@{/logout}" method="post">
    <p><input type="submit" value="從新登陸"/></p>
</form>
<form th:action="@{/select}" method="get">
    <p><input type="submit" value="查看"/></p>
</form>
<form th:action="@{/delete}" method="get">
    <p><input type="submit" value="刪除"/></p>
</form>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
錯誤信息:<h4 th:text="${msg}"></h4>
<form action="" method="post">
    <p>帳號:<input type="text" name="username" value="dalaoyang"/></p>
    <p>密碼:<input type="text" name="password" value="123"/></p>
    <p><input type="submit" value="登陸"/></p>
</form>
</body>
</html>

另外三個跳轉頁面就不貼出來了,panpan帳號登陸能夠查看和刪除,用xiaoli帳號登陸則只有查看而沒有刪除的權限,代碼見下面,sql文件在resources包下html

github代碼java

我的網站mysql

相關文章
相關標籤/搜索