首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何实现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"));

}

}

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180307A0O98300?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券