當前位置:
首頁 > 知識 > 如何實現Shiro基於資料庫的授權認證

如何實現Shiro基於資料庫的授權認證

從一個正常的設計角度來講,用戶、角色、許可權三者的關係數據兩個多個多:

一個用戶擁有多個角色,一個角色屬於多個用戶;

一個角色擁有多個許可權,一個許可權屬於多個角色;

範例:資料庫的創建腳本:

drop database if exists shirodb;

create database shirodb character set utf8;

use shirodb;

create table member (

mid varchar(50),

password varchar(32),

name varchar(20),

locked int,

constraint pk_mid primary key(mid)

);

insert into member(mid,password,name,locked) values("admin","hello","管理員",0);

insert into member(mid,password,name,locked) values("mldn","java","隔壁老王",0);

create table role (

rid int auto_increment,

title varchar(50),

flag varchar(50),

constraint pk_rid primary key (rid)

);

create table member_role (

mid varchar(50),

rid int

);

create table action (

actid int auto_increment,

title varchar(50),

flag varchar(50),

constraint pk_actid primary key (actid)

);

create table role_action (

rid int,

actid int

);

為了方便進行登錄與授權處理,編寫一個單獨的程序類,這個類也不做業務層或數據層的劃分了,只是做了簡單的功能類,此類可以取得用戶的信息以及角色和許可權數據。

定義一個Member數據表的Vo類:

package com.gwolf.vo;

import java.io.Serializable;

public class Member implements Serializable{

private String mid;

private String password;

private String name;

public String getMid() {

return mid;

}

public void setMid(String mid) {

this.mid = mid;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

定義業務層的實現類:MemberLoginService

package com.gwolf.service;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.HashSet;

import java.util.Set;

import com.gwolf.vo.Member;

public class MemberLoginService {

private Connection connection;

private static final String DBDRIVER="org.gjt.mm.mysql.Driver";

private static final String DBURL="jdbc:mysql://localhost:3306/shirodb";

private static final String DBUSER = "root";

private static final String PASSWORD="root";

private PreparedStatement pstmt;

public MemberLoginService() {

this.connectionDataBase();

}

public Member get(String mid) {

Member vo = null;

try {

String sql = "select mid,password from member where mid=?";

this.pstmt = this.connection.prepareStatement(sql);

this.pstmt.setString(1, mid);

ResultSet rs = this.pstmt.executeQuery();

if(rs.next()) {

vo = new Member();

vo.setMid(rs.getString(1));

vo.setPassword(rs.getString(2));

}

} catch (SQLException e) {

e.printStackTrace();

}

return vo;

}

/**

* 根據用戶名查詢出永不對應的所有的角色數據

* @param mid

* @return

*/

public Set listRolesByMember(String mid) {

Set allRoles = new HashSet();

try {

String sql = "select flag from role where rid in"

+ "(select rid from member_role where mid=?)";

this.pstmt = this.connection.prepareStatement(sql);

this.pstmt.setString(1, mid);

ResultSet rs = this.pstmt.executeQuery();

while(rs.next()) {

allRoles.add(rs.getString(1));

}

} catch (SQLException e) {

e.printStackTrace();

}

return allRoles;

}

/**

* 根據用戶名查詢出所有的許可權數據

* @param mid

* @return

*/

public Set listActionByMember(String mid) {

Set allAction = new HashSet();

try {

String sql = "select flag from action where actid in"

+ "(select actid from role_action where rid"

+ " in(select rid from member_role where mid=?))";

this.pstmt = this.connection.prepareStatement(sql);

this.pstmt.setString(1, mid);

ResultSet rs = this.pstmt.executeQuery();

while(rs.next()) {

allAction.add(rs.getString(1));

}

} catch (SQLException e) {

e.printStackTrace();

}

return allAction;

}

public void close() {

if(this.connection!=null) {

try {

this.connection.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

private void connectionDataBase() {

try {

Class.forName(DBDRIVER);

connection = DriverManager.getConnection(DBURL, DBUSER, PASSWORD);

} catch (Exception e) {

e.printStackTrace();

}

}

}

最終這個程序類所取得的全部的角色和許可權數據都是需要交給Shiro判斷的,在整個的處理過程之中,它的判斷是利用Set集合完成的,所以必須返回Set集合。

public Set listRolesByMember(String mid) {

Set allRoles = new HashSet();

try {

String sql = "select flag from role where rid in"

+ "(select rid from member_role where mid=?)";

this.pstmt = this.connection.prepareStatement(sql);

this.pstmt.setString(1, mid);

ResultSet rs = this.pstmt.executeQuery();

while(rs.next()) {

allRoles.add(rs.getString(1));

}

} catch (SQLException e) {

e.printStackTrace();

}

return allRoles;

}

此時的操作不在是簡單的用戶登錄了,但是現在除了用戶登錄之外還牽扯到許可權的操作,所以整個的自定的Realm類就必須更換一個父類:

認證處理類:AuthenticatingRealm。

授權處理類:AuthorizingRealm。

自定義認證授權Realm:

package com.gwolf.shiro.realm;

import org.apache.shiro.authc.AuthenticationException;

import org.apache.shiro.authc.AuthenticationInfo;

import org.apache.shiro.authc.AuthenticationToken;

import org.apache.shiro.authc.IncorrectCredentialsException;

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 com.gwolf.service.MemberLoginService;

import com.gwolf.vo.Member;

public class MyRealm extends AuthorizingRealm {

@Override

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

//登錄認證的方法需要先執行,需要用他來判斷登錄的用戶信息是否合法

String username = (String)token.getPrincipal();

MemberLoginService memberLoginService = new MemberLoginService();

Member vo = memberLoginService.get(username);

memberLoginService.close();

if(vo == null) {

throw new AuthenticationException("改用戶名稱不存在");

}else {

String password = new String((char[])token.getCredentials());

if(vo.getPassword().equals(password)) {

AuthenticationInfo auth = new SimpleAuthenticationInfo(username, password,"memberRealm");

return auth;

}else {

throw new IncorrectCredentialsException("密碼錯誤!");

}

}

}

@Override

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

String username = (String)principals.getPrimaryPrincipal();

SimpleAuthorizationInfo authenticationInfo = new SimpleAuthorizationInfo();

MemberLoginService memberLoginService = new MemberLoginService();

authenticationInfo.setRoles(memberLoginService.listRolesByMember(username));

authenticationInfo.setStringPermissions(memberLoginService.listActionByMember(username));

memberLoginService.close();

return authenticationInfo;

}

}

需要在shiro.ini文件裡面定義相關的Realm配置:

[main]

jdbcRealm=com.gwolf.shiro.realm.MyRealm

securityManager.realm=$jdbcRealm

在單元測試類中測試程序是否正確執行:

package com.gwolf.shiro;

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authc.UsernamePasswordToken;

import org.apache.shiro.config.IniSecurityManagerFactory;

import org.apache.shiro.mgt.SecurityManager;

import org.apache.shiro.subject.Subject;

public class TestLoginDemo {

public static void main(String[] args) {

//取得Factory介面對象,主要的目的是通過配置文件載入文之中的信息,這些信息暫時不能成為認證信息

//取得裡面所保存的所有的認證數據信息

SecurityManager securityManager = new IniSecurityManagerFactory("classpath:shiro.ini").getInstance();

//利用一個專門的認證操作的處理類,實現認證處理的具體實現

SecurityUtils.setSecurityManager(securityManager);

//獲取進行用戶名和密碼認證的介面對象

Subject subject = SecurityUtils.getSubject();

subject.login(new UsernamePasswordToken("admin", "hello"));

System.out.println(subject.isPermitted("member:add"));

}

}


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Adolph談JAVA高端 的精彩文章:

SpringBoot中如何進行Bean配置

TAG:Adolph談JAVA高端 |