成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Spring怎么實(shí)現(xiàn)用戶存儲(chǔ)

這篇文章主要介紹“Spring怎么實(shí)現(xiàn)用戶存儲(chǔ)”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“Spring怎么實(shí)現(xiàn)用戶存儲(chǔ)”文章能幫助大家解決問(wèn)題。

堅(jiān)守“ 做人真誠(chéng) · 做事靠譜 · 口碑至上 · 高效敬業(yè) ”的價(jià)值觀,專業(yè)網(wǎng)站建設(shè)服務(wù)10余年為成都陽(yáng)光房小微創(chuàng)業(yè)公司專業(yè)提供成都定制網(wǎng)頁(yè)設(shè)計(jì)營(yíng)銷網(wǎng)站建設(shè)商城網(wǎng)站建設(shè)手機(jī)網(wǎng)站建設(shè)小程序網(wǎng)站建設(shè)網(wǎng)站改版,從內(nèi)容策劃、視覺設(shè)計(jì)、底層架構(gòu)、網(wǎng)頁(yè)布局、功能開發(fā)迭代于一體的高端網(wǎng)站建設(shè)服務(wù)。

Spring Security

首先,我們看下如何在認(rèn)證的過(guò)程中配置訪問(wèn)用戶數(shù)據(jù)的服務(wù)。

針對(duì)上節(jié)演示的案例,我們需要改進(jìn)的用戶存儲(chǔ),也就是用戶名、密碼以及其他信息存儲(chǔ)的地方,在進(jìn)行認(rèn)證決策的時(shí)候,會(huì)對(duì)其行檢索。而不是寫死的用戶名和隨機(jī)的密碼。

Spring Security非常靈活,能夠基于各種數(shù)據(jù)存儲(chǔ)來(lái)認(rèn)證用戶。它內(nèi)置了許多常見的用戶存儲(chǔ)場(chǎng)景。如: 內(nèi)存,關(guān)系型數(shù)據(jù)庫(kù),以及LDAP。
當(dāng)然,我們也可以編寫并插入自定義的用戶存儲(chǔ)實(shí)現(xiàn)。借助Spring Security的Java配置,我們能夠很容易地配置一個(gè)或多個(gè)數(shù)據(jù)存儲(chǔ)方案。那我們就從最簡(jiǎn)單的開始:在內(nèi)存中維護(hù)用戶存儲(chǔ)。

1 使用基于內(nèi)存的用戶存儲(chǔ)。

我們?cè)谏瞎?jié)的基礎(chǔ)上進(jìn)行改造,因?yàn)槲覀兊陌踩渲妙?SecurityConfig 擴(kuò)展了 WebSecurityConfigurerAdapter ,因此配置用戶存儲(chǔ)最簡(jiǎn)單的方法就是 重載 configure() 方法。

/**
 * @author itguang
 * @create
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("itguang").password("123456").roles("USER").and()
                .withUser("admin").password("123456").roles("ADMIN");
    }
}

我們可以看到,configure方法中的 AuthenticationManagerBuilder 類型的參數(shù),采用了構(gòu)造者風(fēng)格風(fēng)格的接口來(lái)構(gòu)建認(rèn)證配置。
通過(guò)簡(jiǎn)單的調(diào)用 inMemoryAuthentication() 就能啟用基于內(nèi)存的的用戶存儲(chǔ)。
通過(guò) withUser 我們添加了兩個(gè)基于內(nèi)存存儲(chǔ)的用戶,并且分別授予的不同的角色。
withUser()方法返回的是 UserDetailsManagerConfigurer.UserDetailsBuilder ,這個(gè)對(duì)象提供了多個(gè)進(jìn)一步配置用戶的方法。

測(cè)試

接下來(lái),就可以啟動(dòng)項(xiàng)目進(jìn)行測(cè)試了。首先還是訪問(wèn): http://localhost/hello ,會(huì)自動(dòng)動(dòng)跳轉(zhuǎn)到 http://localhost/login 讓我們?nèi)サ顷憽?br/>這次我們就不用再去啟動(dòng)日志中找生成的隨機(jī)密碼了,我們用 上面配置的兩個(gè)用戶分別進(jìn)行測(cè)試,發(fā)現(xiàn)都能夠正確登陸,到這里一個(gè)簡(jiǎn)單的基于內(nèi)存的用戶存儲(chǔ)就完成了。

UserDetailsManagerConfigurer.UserDetailsBuilder除了password()、roles()和and()方法以外,還有其他的幾個(gè)方法可以用來(lái)配置內(nèi)存用戶存儲(chǔ)中的用戶信息

如下表所示:

但是通常來(lái)說(shuō),我們的系統(tǒng)肯定不止兩個(gè)用戶,基于內(nèi)存的用戶存儲(chǔ)還是不能滿足我們的要求,我們期待最好能將數(shù)據(jù)保存在某種關(guān)系型數(shù)據(jù)庫(kù)中。

沒錯(cuò),Spring Security也為我們提供了基于關(guān)系型數(shù)據(jù)庫(kù)的 用戶存儲(chǔ)。

2 使用基于數(shù)據(jù)庫(kù)的用戶存儲(chǔ)

用戶數(shù)據(jù)通常會(huì)存儲(chǔ)在關(guān)系型數(shù)據(jù)庫(kù)中并通過(guò)JDBC進(jìn)行訪問(wèn)。為了配置Spring Security配置以JDBC為支撐的用戶存儲(chǔ)。我們可以使用jdbcAuthentication()方法。

所需的最簡(jiǎn)單的配置如下所示:

/**
 * @author itguang
 * @create
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private DataSource dataSource;

    //基于數(shù)據(jù)庫(kù)表的用戶存儲(chǔ)
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws

在這里我們只需要配置一個(gè)dataSource即可,這樣就可以訪問(wèn)關(guān)系型數(shù)據(jù)庫(kù)了。

其中 dataSource是通過(guò)自動(dòng)裝配的技巧得到的。在springboot下 dataSource 是自動(dòng)裝配的。
我們只需要引入如下依賴

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

        <dependency>
            <groupId>MySQL</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

并在appliciation.properties 中配置spring.datasource 相關(guān)屬性即可。

spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root

Spring Boot就會(huì)使用該配置創(chuàng)建一個(gè)DataSource。并裝配為Spring的一個(gè)bean。因此我們可以直接使用 @Autowired 進(jìn)行注入。

好了,直到目前為止,對(duì)基于數(shù)據(jù)庫(kù)的用戶存儲(chǔ)已經(jīng)配置完畢,你可能回想,那既然基于數(shù)據(jù)庫(kù)了,肯定要在數(shù)據(jù)庫(kù)創(chuàng)建相應(yīng)的表了。那表結(jié)構(gòu)又是怎么樣的呢?

不要著急,接下來(lái)我們就開始數(shù)據(jù)庫(kù)表結(jié)構(gòu)的創(chuàng)建。

回到我們的 SpringSecurityConfig 的配置類,我們看下 jdbcAuthentication 的返回值是: JdbcUserDetailsManagerConfigurer,我們?cè)倏纯?JdbcUserDetailsManagerConfigurer
類中還有哪些方法。

我們主要看下黃框標(biāo)識(shí)出的幾個(gè)方法,

/**
     * Populates the {@link DataSource} to be used. This is the only required attribute.
     *
     * @param dataSource the {@link DataSource} to be used. Cannot be null.
     * @return
     * @throws
    public JdbcUserDetailsManagerConfigurer<B> dataSource(DataSource dataSource)
            throws Exception {
        this.dataSource = dataSource;
        getUserDetailsService().setDataSource(dataSource);
        return this;
    }

    /**
     * Sets the query to be used for finding a user by their username. For example:
     *
     * <code>
     *     select username,password,enabled from users where username = ?
     * </code>
     * @param query The query to use for selecting the username, password, and if the user
     * is enabled by username. Must contain a single parameter for the username.
     * @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
     * customizations
     * @throws
    public JdbcUserDetailsManagerConfigurer<B> usersByUsernameQuery(String query)
            throws Exception {
        getUserDetailsService().setUsersByUsernameQuery(query);
        return this;
    }   
    /**
     * Sets the query to be used for finding a user's authorities by their username. For
     * example:
     *
     * <code>
     *     select username,authority from authorities where username = ?
     * </code>
     *
     * @param query The query to use for selecting the username, authority by username.
     * Must contain a single parameter for the username.
     * @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
     * customizations
     * @throws
    public JdbcUserDetailsManagerConfigurer<B> authoritiesByUsernameQuery(String query)
            throws Exception {
        getUserDetailsService().setAuthoritiesByUsernameQuery(query);
        return this;
    }
    /**
     * An SQL statement to query user's group authorities given a username. For example:
     *
     * <code>
     *     select
     *         g.id, g.group_name, ga.authority
     *     from
     *         groups g, group_members gm, group_authorities ga
     *     where
     *         gm.username = ? and g.id = ga.group_id and g.id = gm.group_id
     * </code>
     *
     * @param query The query to use for selecting the authorities by group. Must contain
     * a single parameter for the username.
     * @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
     * customizations
     * @throws
    public JdbcUserDetailsManagerConfigurer<B> groupAuthoritiesByUsername(String query)
            throws Exception {
        JdbcUserDetailsManager userDetailsService = getUserDetailsService();
        userDetailsService.setEnableGroups(true);
        userDetailsService.setGroupAuthoritiesByUsernameQuery(query);
        return this;
    }

通過(guò)查看源碼以及方法上的注釋,我們發(fā)現(xiàn)這三個(gè)方法主要是用來(lái)配置 用戶查詢(usersByUsernameQuery),權(quán)限查詢(authoritiesByUsernameQuery),
權(quán)限組查詢(groupAuthoritiesByUsername)的sql語(yǔ)句的。并且Spring已經(jīng)給我們配置了默認(rèn)的實(shí)現(xiàn)。

//默認(rèn)的用戶查詢sql
    public static final String DEF_USERS_BY_USERNAME_QUERY = "select username,password,enabled "
            + "from users " + "where username = ?";
  //默認(rèn)的權(quán)限查詢sql
    public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY = "select username,authority "
            + "from authorities " + "where username = ?";
  //默認(rèn)的權(quán)限組查詢sql
    public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY = "select g.id, g.group_name, ga.authority "
            + "from groups g, group_members gm, group_authorities ga "
            + "where gm.username = ? " + "and g.id = ga.group_id "
            + "and g.id = gm.group_id";

當(dāng)然我們完全可以自定義這些語(yǔ)句。就像下面這樣

@Autowired
    private DataSource dataSource;

    //基于數(shù)據(jù)庫(kù)表的用戶存儲(chǔ)
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery("select username,password,enabled,email from users where username=?")
                .authoritiesByUsernameQuery("select username,authority from authorities where username = ?")
                .groupAuthoritiesByUsername("select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id");


    }

接下來(lái),就是按照我們定義的這些語(yǔ)句進(jìn)行表結(jié)構(gòu)的創(chuàng)建了。創(chuàng)建完之后,所有表模型如下圖:

表結(jié)構(gòu)創(chuàng)建語(yǔ)句如下:

DROP TABLE IF EXISTS `authorities`;
CREATE TABLE `authorities` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `authority` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT

-- ----------------------------
-- Table structure for groups
-- ----------------------------
DROP TABLE IF EXISTS `groups`;
CREATE TABLE `groups` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `group_name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT

-- ----------------------------
-- Table structure for group_authorities
-- ----------------------------
DROP TABLE IF EXISTS `group_authorities`;
CREATE TABLE `group_authorities` (
  `group_id` int(11) NOT NULL AUTO_INCREMENT,
  `authority` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`group_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT

-- ----------------------------
-- Table structure for group_members
-- ----------------------------
DROP TABLE IF EXISTS `group_members`;
CREATE TABLE `group_members` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `group_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT

-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(8) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `enabled` tinyint(4) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT

測(cè)試:

現(xiàn)在,基于數(shù)據(jù)庫(kù)的用戶存儲(chǔ)已經(jīng)配置完畢,雖然看起來(lái)比基于內(nèi)存的用戶存儲(chǔ)代碼多,但仔細(xì)查看源碼,還是不難理解的。

我們重新啟動(dòng)應(yīng)用程序,瀏覽器訪問(wèn): http://localhost/hello ,不出意外的有跳轉(zhuǎn)到了 http://localhost/login 讓我們進(jìn)行登陸。但是現(xiàn)在我們的數(shù)據(jù)庫(kù)中并沒有用戶。

所以我們還需要在數(shù)據(jù)庫(kù)中創(chuàng)建用戶,打開數(shù)據(jù)庫(kù),在users表中添加一個(gè)用戶,如下:

我們填入我們新加入的用戶名和密碼,點(diǎn)擊登錄,就會(huì)發(fā)現(xiàn),登陸失?。?/p>

可以看到錯(cuò)誤信息為: Reason: Bad credentials

這是因?yàn)殡m然我們只添加了用戶,但是并沒有為此用戶分配權(quán)限,在 authoritiesByUsernameQuery 執(zhí)行sql時(shí)查詢到的就是null,就會(huì)返回 Bad credentials。

我們只需要在數(shù)據(jù)庫(kù)的 authorities 表中為 itguang 用戶添加一個(gè)權(quán)限即可。

再次登陸,就會(huì)發(fā)現(xiàn)已經(jīng)可以登陸成功。

**對(duì)于最后一個(gè) groupAuthoritiesByUsername 根據(jù)用戶名查詢用戶組權(quán)限的sql,即使查詢?yōu)閚ull,只要是用戶已經(jīng)在 authorities 表中分配了權(quán)限,
就可以登陸成功。對(duì)于 權(quán)限–用戶–角色(用戶組) 的關(guān)系,不清楚的,可以去網(wǎng)上搜一下,有很多文章講的很清楚。**

最后再補(bǔ)充一個(gè)小知識(shí),看一下上面的認(rèn)證查詢,它會(huì)預(yù)期用戶名密碼存儲(chǔ)在了數(shù)據(jù)庫(kù)中。這里唯一的問(wèn)題就是,如果使用明文存儲(chǔ)密碼,會(huì)帶來(lái)安全性問(wèn)題。
但是如果數(shù)據(jù)庫(kù)中的密碼進(jìn)行轉(zhuǎn)碼的話,認(rèn)證就會(huì)失敗,因?yàn)樗c用戶提交的明文密碼并不匹配。

為了解決這個(gè)問(wèn)題,我們需要借助passwordEncoder()方法指定一個(gè)密碼轉(zhuǎn)碼器(encoder)。

@Autowired
    private DataSource dataSource;

    //基于數(shù)據(jù)庫(kù)表的用戶存儲(chǔ)
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery("select username,password,enabled,email from users where username=?")
                .authoritiesByUsernameQuery("select username,authority from authorities where username = ?")
                .groupAuthoritiesByUsername("select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id")
                .passwordEncoder(new StandardPasswordEncoder("53cr3t"));


    }

passwordEncoder()方法可以接受Spring Security中PasswordEncoder接口的任意實(shí)現(xiàn)。
Spring Security的加密模塊包括了三個(gè)這樣的實(shí)現(xiàn):BCryptPasswordEncoder、NoOpPasswordEncoder和StandardPasswordEncoder。

上述的代碼中使用了StandardPasswordEncoder,采用的是 “SHA-256”算法加密實(shí)現(xiàn)。

但是如果內(nèi)置的實(shí)現(xiàn)無(wú)法滿足需求時(shí),你可以提供自定義的實(shí)現(xiàn)。

關(guān)于“Spring怎么實(shí)現(xiàn)用戶存儲(chǔ)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

網(wǎng)站標(biāo)題:Spring怎么實(shí)現(xiàn)用戶存儲(chǔ)
當(dāng)前網(wǎng)址:http://jinyejixie.com/article28/pochcp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)頁(yè)設(shè)計(jì)公司、企業(yè)建站、面包屑導(dǎo)航、做網(wǎng)站、用戶體驗(yàn)網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
莱西市| 凤凰县| 博爱县| 金华市| 东乌| 乃东县| 湘阴县| 栖霞市| 靖安县| 平安县| 海安县| 新平| 南京市| 右玉县| 苗栗县| 冷水江市| 绩溪县| 沙河市| 进贤县| 南宁市| 孟连| 静海县| 喀喇沁旗| 杂多县| 区。| 巴塘县| 通渭县| 元谋县| 南郑县| 图片| 高雄市| 富源县| 定安县| 安义县| 万全县| 二手房| 华蓥市| 铜陵市| 海伦市| 城口县| 曲阳县|