1. 程式人生 > >Spring整合Shiro及簡單實用

Spring整合Shiro及簡單實用

匯入依賴

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>
        

Spring-Context配置相應Bean

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="login.html"/>
        <property name="unauthorizedUrl" value="403.html"/>
        <property name="filterChainDefinitions">
            <value> 
                /login.html = anon  <!--anon的代表是不要認證的-->
                /subLogin = anon
                /* = authc		<!--anon的代表是要認證的,一般放最後-->
            </value>
        </property>
    </bean>

    <!--建立SecurityManager-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="realm" />
    </bean>

    <bean id="realm" class="com.ay.shiro.realm.CustomRealm">
       <!-- <property name="credentialsMatcher" ref="credentialsMatcher"/> -->
    </bean>

    <!--<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="md5" />
        <property name="hashIterations" value="1" />

    </bean>-->

密碼如果使用MD5加密需要credentialsMatcher

自定義Realm

一般 user,role,permission是存在資料庫的3+2表,自定義Realm通過持久層讀取相關需要驗證的資訊。

public class CustomRealm extends AuthorizingRealm {
    {
        super.setName("customRealm");
    }

    @Resource
    private UserDao userDao;

    @Override  //授權
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = (String) principalCollection.getPrimaryPrincipal();
        //模擬獲取roles permission
        Set<String> roles = getRolesByUsername(username);
        Set<String> permission = getPermissionByUsername(username);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(permission);
        return simpleAuthorizationInfo;
    }

    private Set<String> getPermissionByUsername(String username) {
        List<String> permission = userDao.getPermissionByUsername(username);
        if(permission == null){
            return  null;
        }
        Set<String> set = new HashSet<>(permission);
        return set;
    }

    private Set<String> getRolesByUsername(String username) {
        List<String> roles = userDao.getRolesByUsername(username);
        if(roles == null){
            return  null;
        }
        Set<String> set = new HashSet<>(roles);
        return set;
    }

    @Override //認證  主體提交認證後的處理
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String username = (String) authenticationToken.getPrincipal();
        //模擬從資料庫獲取密碼
        String password = getPasswordByUsername(username);
        if(password == null){
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                username,password,"customRealm");
        //對原密碼要進行加鹽,資料庫存的也是要進行加鹽加密的密碼
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(username));
        return authenticationInfo;
    }

    private String getPasswordByUsername(String username) {
        User user = userDao.getUserByUsername(username);
        if(user != null){
            return user.getPassword();
        }
        return null;
    }

    public static void main(String[] args){
        Md5Hash md5Hash = new Md5Hash("123456","Ay");
        System.out.println(md5Hash.toString());
    }
}

控制層

得到主體,生成token,進行認證和授權。

@RequestMapping(value = "/subLogin",method = RequestMethod.POST,
    produces = "application/json;charset=utf-8")
    @ResponseBody
    public String subLogin(User user){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
        try {
            subject.login(token);
//            subject.checkRole("admin");
//            subject.checkPermission("user:select");
        }catch (Exception e){
            return e.getMessage();
        }
        return "登入成功";
    }

通過註釋進行授權

<!--shiro註釋-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

bean配置

<!--開啟shiro註釋-->
    <aop:config proxy-target-class="true"/>
    <bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

示例方法
已認證的使用者需要admin才能訪問

@RequiresRoles("admin")
    @RequestMapping(value = "/testRole",method = RequestMethod.GET)
    @ResponseBody
    public String testRole(){
        return "testRole success";
    }