Apache Shiro

4个POJO

/**
 * @description:菜单
 */
@Entity
@Table(name = "T_MENU")
public class Menu {
    @Id
    @GeneratedValue
    @Column(name = "C_ID")
    private int id;
    @Column(name = "C_NAME")
    private String name; // 菜单名称
    @Column(name = "C_PAGE")
    private String page; // 访问路径
    @Column(name = "C_PRIORITY")
    private Integer priority; // 优先级
    @Column(name = "C_DESCRIPTION")
    private String description; // 描述

    @ManyToMany(mappedBy = "menus")
    private Set<Role> roles = new HashSet<Role>(0);

    @OneToMany(mappedBy = "parentMenu")
    private Set<Menu> childrenMenus = new HashSet<Menu>();

    @ManyToOne
    @JoinColumn(name = "C_PID")
    private Menu parentMenu;
/**
 * @description:权限名称
 */
@Entity
@Table(name = "T_PERMISSION")
public class Permission {

    @Id
    @GeneratedValue
    @Column(name = "C_ID")
    private int id;
    @Column(name = "C_NAME")
    private String name; // 权限名称
    @Column(name = "C_KEYWORD")
    private String keyword; // 权限关键字,用于权限控制
    @Column(name = "C_DESCRIPTION")
    private String description; // 描述

    @ManyToMany(mappedBy = "permissions")
    private Set<Role> roles = new HashSet<Role>(0);
/**
 * @description:角色
 */
@Entity
@Table(name = "T_ROLE")
public class Role {
    @Id
    @GeneratedValue
    @Column(name = "C_ID")
    private int id;
    @Column(name = "C_NAME")
    private String name; // 角色名称
    @Column(name = "C_KEYWORD")
    private String keyword; // 角色关键字,用于权限控制
    @Column(name = "C_DESCRIPTION")
    private String description; // 描述

    @ManyToMany(mappedBy = "roles")
    private Set<User> users = new HashSet<User>(0);

    @ManyToMany
    @JoinTable(name = "T_ROLE_PERMISSION", joinColumns = {
            @JoinColumn(name = "C_ROLE_ID", referencedColumnName = "C_ID") }, inverseJoinColumns = {
                    @JoinColumn(name = "C_PERMISSION_ID", referencedColumnName = "C_ID") })
    private Set<Permission> permissions = new HashSet<Permission>(0);

    @ManyToMany
    @JoinTable(name = "T_ROLE_MENU", joinColumns = {
            @JoinColumn(name = "C_ROLE_ID", referencedColumnName = "C_ID") }, inverseJoinColumns = {
                    @JoinColumn(name = "C_MENU_ID", referencedColumnName = "C_ID") })
    private Set<Menu> menus = new HashSet<Menu>(0);
/**
 * @description:后台用户
 */
@Entity
@Table(name = "T_USER")
public class User {

    @Id
    @GeneratedValue
    @Column(name = "C_ID")
    private int id; // 主键
    @Column(name = "C_BIRTHDAY")
    private Date birthday; // 生日
    @Column(name = "C_GENDER")
    private String gender; // 性别
    @Column(name = "C_PASSWORD")
    private String password; // 密码
    @Column(name = "C_REMARK")
    private String remark; // 备注
    @Column(name = "C_STATION")
    private String station; // 状态
    @Column(name = "C_TELEPHONE")
    private String telephone; // 联系电话
    @Column(name = "C_USERNAME", unique = true)
    private String username; // 登陆用户名
    @Column(name = "C_NICKNAME")
    private String nickname; // 真实姓名

    @ManyToMany
    @JoinTable(name = "T_USER_ROLE", joinColumns = {
            @JoinColumn(name = "C_USER_ID", referencedColumnName = "C_ID") }, inverseJoinColumns = {
                    @JoinColumn(name = "C_ROLE_ID", referencedColumnName = "C_ID") })
    private Set<Role> roles = new HashSet<Role>(0);

在web.xml中配置filter

<!-- 配置 shiro的filter-->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

配置applicationContext-shiro.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa 
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
    
    <!-- 配置Shiro核心Filter  --> 
    <bean id="shiroFilter" 
        class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 安全管理器 -->
        <property name="securityManager" ref="securityManager" />
        <!-- 未认证,跳转到哪个页面  -->
        <property name="loginUrl" value="/login.html" />
        <!-- 登录页面页面 -->
        <property name="successUrl" value="/index.html" />
        <!-- 认证后,没有权限跳转页面 -->
        <property name="unauthorizedUrl" value="/unauthorized.html" />
        <!-- shiro URL控制过滤器规则  -->
        <property name="filterChainDefinitions">
            <value>
                /login.html* = anon
                /user_login.action* = anon 
                /css/** = anon
                /js/** = anon
                /images/** = anon
                /services/** = anon 
                /pages/base/courier.html* = perms[courier:list]
                /pages/base/area.html* = roles[base]
                /** = authc
            </value>
        </property>
    </bean>
    
    <!-- 安全管理器  -->
    <bean id="securityManager" 
        class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="bosRealm" />
    </bean>
    <bean id="lifecycleBeanPostProcessor"
        class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
  

  <!-- 开启shiro注解 -->
  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
    <property name="proxyTargetClass" value="true"></property>
  </bean>
  <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager"></property>
  </bean>


</beans>

基于shiro登录的部分核心代码

        // 基于shiro实现登录
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken authenticationToken = new UsernamePasswordToken(model.getUsername(), model.getPassword());
        
        try {
            subject.login(authenticationToken);
            return SUCCESS;
        } catch (AuthenticationException e) {
            //登录失败
            e.printStackTrace();
            return "login";
        }

realm类

@Service("bosRealm")
public class BosRealm extends AuthorizingRealm{
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //根据当前登录的用户查询对应角色和权限
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        //查询角色
        List<Role> roles = roleService.findByUser(user);
        for (Role role : roles) {
            authorizationInfo.addRole(role.getKeyword());
        }
        //查询权限
        List<Permission> permissions = permissionService.findByUser(user);
        for (Permission permission : permissions) {
            authorizationInfo.addStringPermission(permission.getKeyword());
        }
        return authorizationInfo;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //转换taken
        UsernamePasswordToken passwordToken = (UsernamePasswordToken) token;
        //根据用户名查询用户信息
        User user = userService.findByUsername(passwordToken.getUsername());
        if(user == null) {
            //用户名不存在,
            return null;
        }else {
            //用户名存在
            //当用户返回密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致,
            //密码一致.登录成功,密码不一致,报出异常
            return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        }
    }

}

 applicationContext.xml中开启类注解权限

<!-- 注解管理事务 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

URL 级别粗粒度权限控制
配置 web.xml 的 shiroFilter 拦截 /*
在 spring 的 applicationContext*.xml 配置文件中配置同名 bean,配置

filterChainDefinitions 拦截控制规则
xxx.html* = anon (未登录可以访问)
xxx.html* =authc (必须登录才能访问 )
xxx.html* = perms[权限] (需要特定权限才能访问)
xxx.html* = roles[角色] (需要特定角色才能访问 )

方法级别细粒度权限控制
在 spring 的 applicationContext*.xml 配置 spring aop 对 spring 管理 bean 对象开启 shiro
注解支持
@RequiresPermissions(权限) 需要特定权限才能访问
@RequiresRoles(角色) 需要特定角色才能访问
@RequiresAuthentication 需要认证才能访问

通过 shiro 自定义标签,实现页面元素显示控制
<shiro:authenticated> 登录后才能访问
<shiro:hasPermission name="abc"> 需要特定权限才能访问
<shiro:hasRole name="abc"> 需要特定角色才能访问

在程序中通过代码 判断用户是否具有指定权限( 不太常用 ,有代码侵入 )

权限表达式 “:”代表子权限
权限 courier 包含 courier:add、courier:list、courier:* ,如果用户具有父权限,操作
所有子权限功能

原文地址:https://www.cnblogs.com/learnjfm/p/7347846.html