jfinal 整合shiro的使用

meaven 项目转化为 web 项目并在 tomcat 发布过程:http://www.cnblogs.com/zhanggl/p/4733654.html




shiro 笔记


1.shiro jar导入 


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


       <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-web</artifactId>
   <version>1.4.0</version>
</dependency>
2.shiro.ini 文件




  
[main]
#realm  自定 义 realm 
shiroDbRealm=common.shiro.ShiroDbRealm
securityManager.realms = $shiroDbRealm
# 默认起始页
authc.loginUrl = /passport/
# 登录成功跳转路径 可以自己定义
authc.successUrl = /index
# 退出跳转路径
logout.redirectUrl = /passport/


#路径角色权限设置
[urls]
# /passport/captcha  /passport/login /resources/** 不需要认证就可以访问
/passport/captcha = anon
/passport/login = anon
/resources/** = anon
/passport/logout = logout
# /** 所有路径都要做认证
/** = authc




3.web.xml


            <listener>
   <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
 </listener>

<filter>
   <filter-name>ShiroFilter</filter-name>
   <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
 </filter>
 <filter-mapping>
   <filter-name>ShiroFilter</filter-name>
   <url-pattern>/*</url-pattern>
  
 </filter-mapping>


4. shiro 启动过程


 (1)在项目启动时就会将需要权限角色认证的action加载到内存,
 (2) 用户登录,simpleUser 自己可以重写,自定义参数。在用户校验通过就会把角色信息放进登录用户内,登录成功跳转到成功页。
 (3) 当前用户访问某个action 时 如果加了角色权限认证 ,requireRoles 注解可以自己重写 
    这个是拥有某个角色可以通过
   package common.shiro;


import org.apache.shiro.authz.annotation.Logical;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresRoles {
    String[] value();
    Logical logical() default Logical.OR; // 默认为or,可以是and 


 (4) action 用法 有其一个角色就可以访问
 


   @RequiresRoles( value = {"04", "01"})
  public void look() {
System.err.println("您可以啊,能进来");
renderText("您可以啊,能进来");
}
}






  (5)自己重写的 realm


package common.shiro;


import java.util.HashSet;
import java.util.List;
import java.util.Set;


import javax.annotation.Resource;


import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
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.jfinal.plugin.activerecord.Record;


import common.entity.TRole;
import common.entity.Users;
import common.shiro.user.CaptchaUsernamePasswordToken;
import common.shiro.user.SimpleUser;


public class ShiroDbRealm extends AuthorizingRealm {
    Users dao=new Users().dao();
    TRole roleDao=new TRole().dao();
@Resource
//private UserService userService;

/**
* 当进行角色和权限认证时走此方法
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleUser simpleUser = (SimpleUser) principals.fromRealm(getName()).iterator().next();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if (null == simpleUser) {
return info;
}
String sqlPara="select * from users where username=?";
Users user=dao.findFirst(sqlPara,simpleUser.getUsername());
if (null == user) {
return info;
}


/*List<SysOperate> oplist = shiroDao.getOperateByUserId(user.getId());// 获取用户所有的功能权限
for (SysOperate o : oplist) {
info.addStringPermission(o.getPermission());// 获取资源名称
}*/
Set<String> roleNames = new HashSet<String>();
roleNames.add(simpleUser.getRole());
info.setRoles(roleNames);
return info;
}


/**
* 身份认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
CaptchaUsernamePasswordToken authcToken = (CaptchaUsernamePasswordToken) token;
String sqlPara="select * from users where username=?";
   //校验用户是否存在
Users user=dao.findFirst(sqlPara,authcToken.getUsername());
if (user != null) {
String password = String.valueOf(authcToken.getPassword());
//校验用户密码是否正确
if (password.equals(user.getPassword())) {
SimpleUser simpleUser = new SimpleUser(user.getId(), user.getUsername());
TRole role=roleDao.findById(user.getFkRoleId());
//获取用户的角色名和角色,放进当前用户登录的实例中 注意这可以不放,当用户进行权限角色认证时 还是走 上面的方法 AuthorizationInfo()
simpleUser.setRoleName(role.getRoleName());
simpleUser.setRole(role.getRoleNum());
return new SimpleAuthenticationInfo(simpleUser, password, getName());
} else {
throw new AuthenticationException("密码错误");
}
} else {
throw new UnknownAccountException("用户不存在");
}

}


}




(6)自己重写 ShiroPlugin.java 自己定义页面的跳转路径和action检查


(7)ShiroInterceptor.java 自定义拦截器 对有添加注解action 进行校验




package common.shiro;




import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;


import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.kit.StrKit;


public class ShiroInterceptor implements Interceptor {
/**
* 登录成功时所用的页面。
*/
private final String loginUrl;


/**
* 权限验证失败时所用的页面。
*/
private final String unauthorizedUrl;

/**
* 保存为登陆前的访问页面
*/
private final String savedRequestKey;

public ShiroInterceptor(){
this.loginUrl = ShiroKit.getLoginUrl();
this.unauthorizedUrl = ShiroKit.getUnauthorizedUrl();
this.savedRequestKey = ShiroKit.getSavedRequestKey();
}


public void intercept(Invocation ai) {


        AuthzHandler ah = ShiroKit.getAuthzHandler(ai.getActionKey());
        // 存在访问控制处理器。
        if (ah != null) {
            //System.out.println("权限控制器不为空--------------------------------------");
            try {


                // 执行权限检查。
                ah.assertAuthorized();
            } catch (UnauthenticatedException lae) {


                // RequiresGuest,RequiresAuthentication,RequiresUser,未满足时,抛出未经授权的异常。
                // 如果没有进行身份验证,返回HTTP401状态码,或者跳转到默认登录页面
                if (StrKit.notBlank(ShiroKit.getLoginUrl())) {
                    //保存登录前的页面信息,只保存GET请求。其他请求不处理。
                    if (ai.getController().getRequest().getMethod().equalsIgnoreCase("GET")) {
                        ai.getController().setSessionAttr(ShiroKit.getSavedRequestKey(), ai.getActionKey());
                    }
                    ai.getController().redirect(ShiroKit.getLoginUrl());
                } else {
                    ai.getController().renderError(401);
                }
                return;
            } catch (AuthorizationException ae) {
                // RequiresRoles,RequiresPermissions授权异常
                // 如果没有权限访问对应的资源,返回HTTP状态码403,或者调转到为授权页面




                if (StrKit.notBlank(ShiroKit.getUnauthorizedUrl())) {


                    ai.getController().redirect(ShiroKit.getUnauthorizedUrl());
                } else {
                    ai.getController().renderError(403);
                }
                return;
            }
        }
//System.out.println("权限控制器为空--------------------------------------");
        // 执行正常逻辑
        ai.invoke();
    }
}




(8)JFinalClubConfig.java 配置
//全局拦截器


public void configInterceptor(Interceptors me) {
 //  me.add(new LoginSessionInterceptor());
    me.add(new ShiroInterceptor()); 
    }




 public void configPlugin(Plugins me) {
  //添加shiroPlugin 
        ShiroPlugin shiroPlugin = new ShiroPlugin(this.routes);
me.add(shiroPlugin);
  
    }




 public void configEngine(Engine me) {
    //配置全局方法
    me.addDirective("hasRole",new shiroTagForHasRole());
    }


(9) 自定义的simpleUser




package common.shiro.user;


import java.io.Serializable;




public class SimpleUser implements Serializable{
private static final long serialVersionUID = 1L;
private final Integer id;
private final String username;
private final String name;
private String roleName;
private String role;
public SimpleUser(Integer id, String username,String name) {
this.id = id;
this.username = username;
this.name = name;
}


public SimpleUser(Integer id, String username) {
this.id = id;
this.username = username;
this.name = username;
}


public final Integer getId() {
return id;
}
/**
* @Title: getUsername  
* @Description: 获得用户名 
* @return 
* @since V1.0.0
*/
public final String getUsername() {
return username;
}
/**
* @Title: getRoleName  
* @Description: 获得角色名称 
* @return 
* @since V1.0.0
*/
public final String getRoleName() {
return roleName;
}
/**
* @Title: setRoleName  
* @Description: 设定角色名称  
* @param roleName 
* @since V1.0.0
*/
public final void setRoleName(String roleName) {
this.roleName = roleName;
}
public final String getRole() {
return role;
}
public final void setRole(String role) {
this.role = role;
}
public String getName() {
return name;
}

}
(10) 全局方法 是否拥有角色 或权限 获取当前用户 等功能




package common.shiro;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;


/**
 * ShiroMethod. (SPI, Singleton, ThreadSafe)
 *
 * @author dafei (myaniu AT gmail DOT com)
 */
public class ShiroMethod {


private static final String NAMES_DELIMETER = ",";


/**
* 禁止初始化
*/
private ShiroMethod() {}


/**
* 获取 Subject
*
* @return Subject
*/
protected static Subject getSubject() {
return SecurityUtils.getSubject();
}


/**
* 验证当前用户是否属于该角色?,使用时与lacksRole 搭配使用
*
* @param roleName
*            角色名
* @return 属于该角色:true,否则false
*/
public static boolean hasRole(String roleName) {
return getSubject() != null && roleName != null
&& roleName.length() > 0 && getSubject().hasRole(roleName);
}


/**
* 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。
*
* @param roleName
*            角色名
* @return 不属于该角色:true,否则false
*/
public static boolean lacksRole(String roleName) {
return !hasRole(roleName);
}


/**
* 验证当前用户是否属于以下任意一个角色。
*
* @param roleNames
*            角色列表
* @return 属于:true,否则false
*/
public static boolean hasAnyRoles(String roleNames) {
boolean hasAnyRole = false;
Subject subject = getSubject();
if (subject != null && roleNames != null && roleNames.length() > 0) {
// Iterate through roles and check to see if the user has one of the
// roles
for (String role : roleNames.split(NAMES_DELIMETER)) {
if (subject.hasRole(role.trim())) {
hasAnyRole = true;
break;
}
}
}
return hasAnyRole;
}


/**
* 验证当前用户是否属于以下所有角色。
*
* @param roleNames
*            角色列表
* @return 属于:true,否则false
*/
public static boolean hasAllRoles(String roleNames) {
boolean hasAllRole = true;
Subject subject = getSubject();
if (subject != null && roleNames != null && roleNames.length() > 0) {
// Iterate through roles and check to see if the user has one of the
// roles
for (String role : roleNames.split(NAMES_DELIMETER)) {
if (!subject.hasRole(role.trim())) {
hasAllRole = false;
break;
}
}
}
return hasAllRole;
}


/**
* 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用
*
* @param permission
*            权限名
* @return 拥有权限:true,否则false
*/
public static boolean hasPermission(String permission) {
return getSubject() != null && permission != null
&& permission.length() > 0
&& getSubject().isPermitted(permission);
}


/**
* 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。
*
* @param permission
*            权限名
* @return 拥有权限:true,否则false
*/
public static boolean lacksPermission(String permission) {
return !hasPermission(permission);
}


/**
* 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。与notAuthenticated搭配使用
*
* @return 通过身份验证:true,否则false
*/
public static boolean authenticated() {
return getSubject() != null && getSubject().isAuthenticated();
}


/**
* 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。。
*
* @return 没有通过身份验证:true,否则false
*/
public static boolean notAuthenticated() {
return !authenticated();
}


/**
* 认证通过或已记住的用户。与guset搭配使用。
*
* @return 用户:true,否则 false
*/
public static boolean user() {
return getSubject() != null && getSubject().getPrincipal() != null;
}


/**
* 验证当前用户是否为“访客”,即未认证(包含未记住)的用户。用user搭配使用
*
* @return 访客:true,否则false
*/
public static boolean guest() {
return !user();
}


/**
* 输出当前用户信息,通常为登录帐号信息。
* @return 当前用户信息
*/
public String principal(){
if (getSubject() != null) {
            // Get the principal to print out
            Object principal = getSubject().getPrincipal();
            return principal.toString();
        }
return "Guest";
}
}



Spring Boot 3整合Shiro和JWT可参考下面的通用思路,虽然未明确是Spring Boot 3,但基础整合逻辑适用: 1. **引入依赖**:添加Shiro、JWT和Redis的依赖项,以在项目中使用这些工具进行权限管理和认证验证[^2]。以下是Maven依赖示例: ```xml <dependencies> <!-- Shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.9.1</version> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <!-- Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> ``` 2. **配置Shiro**:配置Shiro的安全管理器、Realm等。安全管理器负责管理Shiro的安全操作,Realm用于从数据源(如数据库)中获取用户信息和权限信息。示例代码如下: ```java import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); return shiroFilterFactoryBean; } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); chainDefinition.addPathDefinition("/login", "anon"); // 登录接口放行 chainDefinition.addPathDefinition("/**", "authc"); // 其他接口需要认证 return chainDefinition; } } ``` 3. **实现JWT工具类**:生成JWT Token、验证Token等功能。JWT工具类封装了JWT的创建、验证等操作。示例代码如下: ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; import java.util.HashMap; import java.util.Map; public class JwtUtils { private static final String SECRET_KEY = "your_secret_key"; private static final long EXPIRATION_TIME = 86400000; // 24小时 public static String generateToken(String username) { Map<String, Object> claims = new HashMap<>(); claims.put("username", username); return Jwts.builder() .setClaims(claims) .setSubject(username) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } public static Claims validateToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); } } ``` 4. **Controller层实现**:实现登录接口和受保护资源的访问接口。登录接口用于生成JWT Token,受保护资源的访问接口需要验证Token。示例代码如下: ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @PostMapping("/login") public String login(@RequestParam String username, @RequestParam String password) { Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { subject.login(token); return JwtUtils.generateToken(username); } catch (AuthenticationException e) { return "登录失败"; } } @GetMapping("/protected") public String protectedResource() { return "这是受保护的资源"; } } ``` 此外,也有开发出的最简单的整合方式fastdep - shiro - jwt,可参考其源码地址进行整合,能结合常用运用场景,降低配置难度,提高开发效率,适用于各类无状态微服务应用 [^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值