springBoot+shiro+web

3.1乐导、pom.xml文件

<dependency>
           <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
           <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.8</version>
        </dependency>

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

        <!-- Spring Boot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.1</version>
        </dependency>

        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
        </dependency>

3.2、配置文件

dataSource=org.springframework.jdbc.datasource.DriverManagerDataSource
#數(shù)據(jù)庫url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
#數(shù)據(jù)庫賬號
spring.datasource.username=root
#數(shù)據(jù)庫密碼
spring.datasource.password=123456
spring.driver-class-name=com.mysql.jdbc.Driver
server.port=8044

#mybatis的 xml 文件:放在resources下面
mybatis.mapper-locations=classpath:repository/*.xml
#這個配置使用的mapper文件所在目錄
mybatis.type-aliases-package=com.huihui.chapter2.mapper


# 頁面訪問路徑
spring.thymeleaf.prefix=/WEB-INF/views/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false

#################################################日志####################################################
#com.mycompany.mavenspringboot.mapper sql日志 DEBUG級別輸出
logging.level.com.huihui.chapter2.mapper=DEBUG
logging.file=logs/spring-boot-logging.log
logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n
logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n

3.3浸颓、數(shù)據(jù)庫設(shè)計
數(shù)據(jù)庫跟上一篇一樣物臂,看過的跳過
shiro_user表:

DROP TABLE IF EXISTS `shiro_user`;
CREATE TABLE `shiro_user`  (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `USER_NAME` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `PASSWORD` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  PRIMARY KEY (`ID`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
INSERT INTO `shiro_user` VALUES (1, 'test', '123456');

shiro_user_role表:

DROP TABLE IF EXISTS `shiro_user_role`;
CREATE TABLE `shiro_user_role`  (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `USER_NAME` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `ROLE_NAME` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  PRIMARY KEY (`ID`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
INSERT INTO `shiro_user_role` VALUES (1, 'test', 'role1');

shiro_role_permission表:

DROP TABLE IF EXISTS `shiro_role_permission`;
CREATE TABLE `shiro_role_permission`  (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `ROLE_NAME` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  `PERM_NAME` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  PRIMARY KEY (`ID`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
INSERT INTO `shiro_role_permission` VALUES (1, 'role1', 'perm1');

3.4旺拉、程序的入口
Application.java類是springBoot程序的入口


@SpringBootApplication
//掃描你項目所有的java類
@ComponentScan(basePackages = {"com.huihui"})
//掃描mapper所在的位置
@MapperScan({"com.huihui.chapter2.mapper"})
public class Application {

    public static void main(String[] args) throws Exception{
        SpringApplication.run(Application.class,args);

    }

}

3.5、開始寫接口代碼
先看一下項目的結(jié)構(gòu)

image.png

代碼從數(shù)據(jù)庫開始寫起:

@Repository
public interface UserMapper {

    String queryUserPassword(@Param("userName")String userName);

    List<String> queryUserRole(@Param("userName")String userName);

    List<String> queryRolePermission(@Param("roleName")String roleName);

    List<String> queryUserPermission(@Param("userName")String userName);
}

mapper對應(yīng)的xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.huihui.chapter2.mapper.UserMapper">
    <select id="queryUserPassword" resultType="string">
      select password from shiro_user where user_name = #{userName, jdbcType=VARCHAR}
    </select>
    <select id="queryUserRole" resultMap="roleMap">
      select role_name from shiro_user_role where user_name = #{userName, jdbcType=VARCHAR}
    </select>

    <resultMap id="permissionMap" type="java.lang.String">
        <result column="perm_name" jdbcType="VARCHAR"/>
    </resultMap>
    <resultMap id="roleMap" type="java.lang.String">
        <result column="role_name" jdbcType="VARCHAR"/>
    </resultMap>

    <select id="queryUserPermission" resultMap="permissionMap">
      SELECT
        srp.perm_name
          FROM
            shiro_user_role sur
            INNER JOIN shiro_role_permission srp ON sur.role_name = srp.role_name
          WHERE
            sur.user_name = #{userName, jdbcType=VARCHAR}
    </select>
    <select id="queryRolePermission" resultMap="permissionMap">
      select perm_name from shiro_role_permission where role_name = #{roleName, jdbcType=VARCHAR}
    </select>
</mapper>

接下來是service:


@Service
public class UserService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    MyUserRealm myUserRealm;

    /**
     * 登錄
     * @param username
     * @param password
     * @throws Exception
     */
    public void doLogin(String username, String password) throws Exception {
        Subject currentUser = SecurityUtils.getSubject();

        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            token.setRememberMe(true);//是否記住用戶
            try {
                currentUser.login(token);//執(zhí)行登錄
            } catch (UnknownAccountException uae) {
                throw new Exception("賬戶不存在");
            } catch (IncorrectCredentialsException ice) {
                throw new Exception("密碼不正確");
            } catch (LockedAccountException lae) {
                throw new Exception("用戶被鎖定了 ");
            } catch (AuthenticationException ae) {
                ae.printStackTrace();
                throw new Exception("未知錯誤");
            }
        }
    }

    /**
     * 根據(jù)用戶名查詢密碼
     * @param userName
     * @return
     */
    public String queryUserPassword(String userName){
        return userMapper.queryUserPassword(userName);
    }

    /**
     * 查詢當前用戶對應(yīng)的權(quán)限
     * @param userName
     * @return
     */
    public List<String> queryUserPermission(String userName){
        return userMapper.queryUserPermission(userName);
    }

}

controller:


@Controller
public class UserController {

    @Autowired
    UserService userService;

    @RequestMapping(value = "/index",method = RequestMethod.POST)
    public String goLogin() {
        return "/index.html";
    }

    @RequestMapping(value = "/logout",method = RequestMethod.POST)
    public String login() {
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.logout();
        return "/index.html";
    }

    @RequestMapping(value = "/",method = RequestMethod.GET)
    public String index() {
        return "/index.html";
    }

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(String username, String password) {
        try {
            userService.doLogin(username, password);
        } catch (Exception e) {
            return "redirect:/hello";
        }
        return "redirect:/hello";
    }

    @RequestMapping(value = "/hello")
    public String hello(){
        return "hello.html";
    }

    @RequestMapping(value = "/hello1")
//需要訪問此接口的權(quán)限
    @RequiresPermissions("perm3")
    public String hello1(){
        return "hello2.html";
    }

}

寫一個異常攔截器棵磷,攔截沒有權(quán)限和未登錄的異常:


@ControllerAdvice
public class ExceptionInterceptor {

    @ExceptionHandler({ UnauthorizedException.class, AuthorizationException.class })
    public String authorizationException(HttpServletRequest req, HttpServletResponse response, Exception e)  {
        return "沒有權(quán)限";
    }

    @ExceptionHandler({ UnauthenticatedException.class, AuthenticationException.class })
    public String authenticationException(HttpServletRequest req, HttpServletResponse response, Exception e)  {

        return "請登錄";
    }

}

寫一個Realm繼承AuthorizingRealm账阻,重寫獲取權(quán)限,登錄等方法:


public class MyUserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    public AuthorizationInfo queryAuthorizationInfo(PrincipalCollection principals){
        return this.getAuthorizationInfo(principals);
    }

    // 獲取用戶的權(quán)限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        String userName = principals.fromRealm(getName()).iterator().next().toString();
        if(userName != null){
            //獲取用戶所有權(quán)限  根據(jù)自己的需求編寫獲取授權(quán)信息泽本,這里簡化代碼獲取了用戶對應(yīng)的所有權(quán)限
            List<String> perms = userService.queryUserPermission(userName);
            if(perms != null && !perms.isEmpty()){
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                for(String each : perms){
                    //將權(quán)限添加到用戶信息中
                    info.addStringPermission(each);
                }
                return info;
            }
        }

        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        //通過表單接受的用戶名淘太,調(diào)用currentUser.login的時候執(zhí)行
        String userName = token.getUsername();
        if(userName != null && !"".equals(userName)){
            //查詢密碼
            String password = userService.queryUserPassword(userName);
            if(password != null){
                return new SimpleAuthenticationInfo(userName,password,getName());
            }
        }

        return null;
    }

    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

}

接下來寫一些配置的屬性,可以寫在配置文件里面规丽,也可以用java類代替蒲牧,我這邊是用java類直接寫的:


@Configuration
public class ShiroUserConfig {

    @Bean
    public MyUserRealm myUserRealm(){
        MyUserRealm realm = new MyUserRealm();
        return realm;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager webSecurityManager = new DefaultWebSecurityManager();
        webSecurityManager.setRealm(myUserRealm());
        return webSecurityManager;
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager());
        // 配置訪問權(quán)限
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        //filterChainDefinitionMap.put("/index", "anon"); // 表示可以匿名訪問
//      filterChainDefinitionMap.put("/*", "authc");// 表示需要認證才可以訪問
//      filterChainDefinitionMap.put("/user/login", "perms[權(quán)限添加]");

        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return factoryBean;
    }


    /***  開啟Shiro的注解*/
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

OK,接口準備完畢了赌莺,接下來寫幾個簡單的頁面測試一下:


image.png

index.html

<form method="post" action="/login">
    <div>
        賬號: <input type="text" value="test" name="username" id="username" placeholder="賬號">
    </div>
    <div>
        密碼: <input type="password" value="123456" class="form-control" name="password" id="password" placeholder="密碼">
    </div>
    <button type="submit">提交</button>
</form>

hello.html

<form action="/logout" method="post">
    <button type="submit">退出</button>
</form>
<form method="post" action="/hello1">
    <button type="submit">hello2</button>
</form>

hello2.html跟error.html隨便寫點東西

OK冰抢,到這里代碼及寫完了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市艘狭,隨后出現(xiàn)的幾起案子挎扰,更是在濱河造成了極大的恐慌,老刑警劉巖巢音,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遵倦,死亡現(xiàn)場離奇詭異,居然都是意外死亡官撼,警方通過查閱死者的電腦和手機梧躺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來傲绣,“玉大人掠哥,你說我怎么就攤上這事⊥核校” “怎么了续搀?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長菠净。 經(jīng)常有香客問我禁舷,道長,這世上最難降的妖魔是什么嗤练? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任榛了,我火速辦了婚禮,結(jié)果婚禮上煞抬,老公的妹妹穿的比我還像新娘霜大。我一直安慰自己,他們只是感情好革答,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布战坤。 她就那樣靜靜地躺著曙强,像睡著了一般。 火紅的嫁衣襯著肌膚如雪途茫。 梳的紋絲不亂的頭發(fā)上碟嘴,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機與錄音囊卜,去河邊找鬼娜扇。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播圆存,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼刃麸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起司浪,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤泊业,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啊易,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吁伺,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年认罩,在試婚紗的時候發(fā)現(xiàn)自己被綠了箱蝠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡垦垂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牙瓢,到底是詐尸還是另有隱情劫拗,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布矾克,位于F島的核電站页慷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏胁附。R本人自食惡果不足惜酒繁,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望控妻。 院中可真熱鬧州袒,春花似錦、人聲如沸弓候。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至夸研,卻和暖如春邦蜜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背亥至。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工悼沈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人姐扮。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓井辆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親溶握。 傳聞我的和親對象是個殘疾皇子杯缺,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 兒子咳嗽沒好,趁著他在做霧化寫寫我的親子日記睡榆。 晚上收拾好萍肆,我跟他說洗腳,刷牙要睡覺了胀屿,我就在忙我的塘揣。...
    李尚宸閱讀 213評論 0 0
  • 張廷貴老師2016/8/12張權(quán)2018/12/22 成功對一個心理的發(fā)展太寶貴了,既可以振奮精神宿崭,又可以去除病痛...
    點心燈張權(quán)閱讀 231評論 0 0
  • 病了一場亲铡,住了幾天的院,以為調(diào)整好了可以完全的重新收拾一下自己的生活了葡兑,卻發(fā)現(xiàn)最終還是難逃現(xiàn)狀奖蔓,慢慢的一點點吧。生...
    不丑的丑哥閱讀 206評論 0 1
  • 如果內(nèi)容是一個人疑务,那視頻包裝就是這個人的衣服。穿上“衣服”的內(nèi)容梗醇,才會 更好看知允。特別是傳統(tǒng)媒體行業(yè),包裝就已經(jīng)是視...
    每次看到閱讀 1,422評論 0 0
  • 第一步:cd到該文件的目錄下 第二步:vi 要編輯的文件名叙谨,進入普通模式温鸽,(可以查看文件內(nèi)容) 第三步:輸入 i ...
    天狠藍閱讀 8,105評論 0 1