新人はSpringSecurityの基本原則を理解しています

Spring Securityは、Springが提供するセキュリティコンポーネントであり、主にプロジェクト内のユーザーのIDを識別および認証するために使用されます。

SpringセキュリティフレームワークはSpring-Securityであり、現在のプロジェクトのユーザーログインとログイン後の権限管理を管理する機能であり、Springフレームワークが提供する権限管理とセキュリティソリューションです。

Spring-Securityフレームワークと同様の機能を持つフレームワークはShiroです

Spring Securityを使用する前に、依存関係を追加する必要があります。依存関係は、SpringBootプロジェクトの作成時に直接確認できます。または、作成済みのプロジェクトに追加することもできます。

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

依存関係を追加した後、サービスを開始すると、ランダムに生成されたパスワードの文字列が表示されます。これを使用して、Spring-Securityシステムにログインできます。

ユーザー名:ユーザーパスワードは、サービスの開始時に生成される文字列です。

この依存関係が読み込まれたら、最初にSpring-Securityにログインして、現在のプロジェクトのリソースにアクセスする必要があります。

ユーザー名とパスワードをカスタマイズしたい場合

次に、application.propertiesファイルで指定する必要があります

コードは以下のように表示されます

spring.security.user.name=admin
spring.security.user.password=666666

上記の構成では、サービスの開始時にランダムなパスワードは生成されず、構成されたユーザー名とパスワードでログインできます。

実際の開発では、パスワードをプレーンテキストで保存することはできません。プレーンテキストのパスワードは、セキュリティを向上させるために、特定の暗号化アルゴリズムに従って暗号文パスワードに暗号化できます。現在、一般的な暗号化アルゴリズムには、md5、Bcryptなどがあります。

私たちのプロジェクトでは、Spring Securityに付属のBcrypt暗号化を使用しています。Bcryptを使用してプレーンテキストのパスワードを暗号化および検証する操作を実装しましょう。

まず、暗号化されたオブジェクトをSpringコンテナに挿入し、プロジェクトにセキュリティパッケージを作成し、パッケージにSecurityConfigクラスを作成します。

// @Configuration表示当前这个类也是Spring的配置类
// Spring扫描到这类时,就会把它当做配置类解析
@Configuration
public class SecurityConfig {
    //向spring容器中注入一个加密对象,用于对密码加密
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

テスト:

 @Autowired
    PasswordEncoder passwordEncoder;
    //加密
    @Test
    public void encode(){
        String pwd=passwordEncoder.encode("666666");
        System.out.println(pwd);
        //$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq
    }
    //验证
    @Test
    public void decode(){
        boolean bool=passwordEncoder.matches("666666",
   "$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq");
        System.out.println(bool);
    }

プロジェクトがPasswordEncoderタイプのオブジェクトを挿入すると、SpringSecurityフレームワークはこのオブジェクトを自動的に使用して現在のプレーンテキストのパスワードを暗号化し、application.propertiesファイル内のユーザーのパスワードを暗号化されたものに変更する必要があります。

application.propertiesログイン構成は次のように変更されます

spring.security.user.name=admin
spring.security.user.password=$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq

パスワードの暗号化が必要な場合、PasswordEncoderオブジェクトの挿入を構成クラスに追加する必要があります。これは非常に面倒です。

暗号文パスワードに特定のアルゴリズムIDを追加すると、SpringSecurityは暗号化アルゴリズムに従って自動的に暗号化します。これはより簡単です。

具体的な方法は次のとおりです。application.propertiesの変更

spring.security.user.name=admin
spring.security.user.password={bcrypt}$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq

このようにして、SecurityConfigクラスに挿入されたPasswordEncoderに注釈を付けたり削除したりできます

@Configuration
public class SecurityConfig {

    //向spring容器中注入一个加密对象,用于对密码加密
    /*@Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }*/
}

プロジェクトには多くのユーザーがいて、それらはすべてデータベースに保存されています。構成ファイルの構成ではログインできないため、Javaコードでログインを確認する方法を学ぶ必要があります。この一連の確認操作はJava構成クラスで記述する必要があります

上記の章で作成したSecurityConfigを使用するだけです!!!

コード例:

@Configuration
//下面的注解表示开启Spring-Security的权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //配置登录验证(即用户名和密码的验证)
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.inMemoryAuthentication().withUser("tom")
                .password("{bcrypt}$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq")
                //上面的配置是规定了用户的用户名和密码,可以使用他们登录
                //下面的配置是规定了这个用户的特定权限
                //有了这个特定权限才可以访问特定的方法
                .authorities("/user/get");

    }
}

上記のコードでは、tomと正しいパスワードを使用して一般的なリソースにアクセスできますが、特別な権限を持つリソースにアクセスできない場合は、前に作成したUserControllerクラスのメソッドを書き直します。

リクエストパスを設計するときは、{}を使用してリクエストパスの名前をフレームに入れ、変数を表すことができます。後でクライアントがリクエストを送信すると、{}プレースホルダーに対応する場所は任意のデータになります。{}プレースホルダーがリクエストパスで使用されている場合、リクエストを処理するメソッドのパラメーターリストで、パラメーター宣言の前に@PathVariableアノテーションを追加して、プレースホルダーの値を取得します。RESTFULスタイルのAPIであるURLにコアパラメーターを配置します。

@RestController
@RequestMapping("/test")
public class TestController {
 
    @Autowired
    private IUserService userService;
 
    // http://localhost:8080/test/user/1
    @GetMapping("/user/{id}")
    public User getUserById(@PathVariable("id") Integer id) {
        return userService.getById(id);
    }
 
}

あなたは上記のURLへのアクセスを制限する必要がある場合は、例えば、一部のユーザーがアクセスすることができますが、いくつかの他のユーザーがアクセスすることはできません、次のような、自分で「認証文字列」を設計することができ"a"たりなど!一般的な使用などのアクセス権限、定義するためにURLのスタイルを使用することが推奨されるかを"hello""test:user:info""/user/user/info"

@GetMapping("/user/{id}")
@PreAuthorize("hasAuthority('test:user:info')")
public User getUserById(@PathVariable("id") Integer id) {
    return userService.getById(id);
}

注:権限文字列のデザインは、URLのデザインとは何の関係もありません。

リクエスト@PreAuthorize処理するメソッドの前に、「リクエストされたパスにアクセスするには特定の権限が必要」と宣言するアノテーションを設定できます。次に例を示します。

コード例:

//实际访问路径为:localhost:8080/v1/users/get?id=1
    @GetMapping("/get")
    @PreAuthorize("hasAuthority('/user/get')")//设置访问这个方法的特殊权限
    public User get(Integer id){
        User u=userService.getById(id);
        return u;
    }
    @GetMapping("/list")
    @PreAuthorize("hasAuthority('/user/list')")
    public List<User> list(){
        List<User> list=userService.list();
        return list;
    }

上記の注釈構成について:

アノテーション名@PreAuthorizeは、「リクエストを処理する前に権限を確認する」ことを意味します。

注釈属性のhasAuthorityは、「特定の権限が必要」を意味します。

アノテーション属性の/ user / listは、単なる識別であるカスタム権限文字列です。

 ユーザーログイン-UserDetailsS​​erviceインターフェースUserDetailsS​​erviceを使用して認証データを提供します

Spring SecurityUserDetailsServiceインターフェースを定義し、インターフェースには抽象的なメソッドがあります

UserDetailsS​​erviceは、Spring Securityによって提供されるインターフェイスです。このインターフェイスで定義されたメソッドは、タイプUserDetailsのオブジェクトを返します。このオブジェクトには、ユーザー、ユーザー名\パスワード\権限などに関するさまざまな情報が含まれます。

このインターフェイスを実装するクラスを記述しますUserDetailsS​​erviceImplコードは次のとおりです。

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

 このメソッドの機能は次のとおりです。ユーザー名を指定して、ユーザーの詳細情報(返却する必要があるUserDetailsタイプのオブジェクト)をした後。春のセキュリティは、ユーザーの詳細情報を取得し、それが自動的にユーザーの本人確認を完了します、後にユーザ権限情報を含みます検証は成功します。フレームワークが扱うことは、開発者として、「ユーザー名に基づいてユーザーの詳細を取得する」という問題を解決するだけです。

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String name)
            throws UsernameNotFoundException {
        UserDetails user=null;
        //判断用户是不是jerry
        if("jerry".equals(name)){
            //设置jerry用户的详情
            user= User.builder()
                    .username("jerry")
                    .password("{bcrypt}$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq")
                    .authorities("/user/get")
                    .build();
        }
        return user;
    }
}

注:上記のクラスは、コンポーネントによってスキャンされ、@Component注釈が付けられたパッケージに含まれている必要があります。そうすると、Springフレームワークが上記のクラスのオブジェクトを自動的に作成および管理し、このクラスのオブジェクトを直接アセンブルできます。

次に、SecurityConfigクラスに戻り、上記のクラスのオブジェクトを適用します。

次に、SecurityConfigクラスの宣言の前に@EnableGlobalMethodSecurity(prePostEnabled = true)アノテーションを追加して、アクセス許可チェックを許可する必要があります。例えば:

@Configuration
//下面的注解表示开启Spring-Security的权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired(required = false)
    UserDetailsServiceImpl userDetailsService;

    //配置登录验证(即用户名和密码的验证)
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.userDetailsService(userDetailsService);

    }

}

厳密に言えば、上記の方法は「ログイン」方法ではなく、「ユーザー詳細を取得する」方法であり、ログインが成功したかどうかさえわからないため、パラメータリストにパスワードがありません。将来的には、Spring Securityは上記のメソッドによって返されるオブジェクトを取得し、パスワードが正しいことなどを確認します。

Spring-Securityは接続クエリを使用してユーザー権限を取得します

ユーザーの詳細を照会するには、2つの方法があります。1つは、ユーザー名に基づいてユーザー情報を照会する方法と、上記のユーザーIDに基づいてアクセス許可を照会して、ログインに必要なすべての情報を取得する方法です。

UserMapperインターフェースの例では:

@Repository
public interface UserMapper extends BaseMapper<User> {

    // 根据用户的id查询用户的所有权限
    @Select("SELECT p.id,p.name" +
            "FROM user u" +
            "LEFT JOIN user_role ur ON u.id=ur.user_id" +
            "LEFT JOIN role r ON r.id=ur.role_id" +
            "LEFT JOIN role_permission rp ON r.id=rp.role_id" +
            "LEFT JOIN permission p ON p.id=rp.permission_id" +
            "WHERE u.id=#{id}")
    List<Permission> findUserPermissionById(Integer id);

    //按用户名查询用户
    @Select("select * from user where username=#{username}")
    User findUserByUsername(String username);
}

作成されたプログラムの基本原則は、独自のサービスレイヤーによって独自に作成されたマッパーを呼び出すことです。この呼び出しは非常に特殊です。サービスを呼び出すのはコントローラーではなく、SpringSecurityです。最初にIUserServiceインターフェイスでメソッドを宣言します。

public interface IUserService extends IService<User> {

    //根据用户名获得用户认证信息的业务逻辑层方法
    UserDetails getUserDetails(String username);

}

次に、実装クラスUserServiceImplに実装します。

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails getUserDetails(String username) {
        //根据用户名查询出用户对象
        User user=userMapper.findUserByUsername(username);
        // 如果用户为空,表示用户名不存在,返回登录失败
        if(user==null){
            return null;
        }
        //根据用户id查询用户权限
        List<Permission> ps=userMapper
                .findUserPermissionById(user.getId());
        //将查询到的所有权限名称填装到一个数组中
        String[] auths=new String[ps.size()];
        int i=0;
        for(Permission p: ps){
            auths[i++]=p.getName();
        }
        //构建UserDetails
        UserDetails u= org.springframework.security.core
                .userdetails.User.builder()
                .username(user.getUsername())
                .password(user.getPassword())
                .authorities(auths)
                //getLocked默认都是0,所以要判==1得到false表示不锁定
                .accountLocked(user.getLocked()==1)
                //getEnabled默认都是1,所以要判==0得到false表示可用
                .disabled(user.getEnabled()==0)
                .build();
        return u;//一定不要返回null!!!!
    }
}

最後に、UserDetailsS​​erviceImplクラスのコード例をリファクタリングします。

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private IUserService userService;
    @Override
    public UserDetails loadUserByUsername(String name)
            throws UsernameNotFoundException {
        UserDetails user=userService.getUserDetails(name);
        return user;
    }
}

ユーザーログイン-アクセス制御について(インターセプターと同等)

承認スコープを制御し、ログインページの承認スコープコントロールをカスタマイズします

実際、アクセスするためにWebサイトのすべてのページリソースにログインする必要はないため、Spring Securityの制限戦略は比較的厳格です。これらの認証範囲を自分で設定する場合は、次のコードが必要です。メソッドコードをに追加します。 SecurityConfigクラスは次のとおりです

SecurityConfig書き換えprotected void configure(HttpSecurity http)方法:

/设置SpringSecurity的授权范围和登录页面
  @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()   //关闭防跨域攻击
            .authorizeRequests()//开始设置授权范围
            .antMatchers(
                    "/index.html",
                    "/img/*",
                    "/js/*",
                    "/css/*",
                    "/bower_components/**",
                    "/login.html"
                    ).permitAll()     //上面路径允许直接访问
                .anyRequest().authenticated()//其他的资源需要登录
                .and().formLogin()//登录方式是表单
                .loginPage("/login.html")//指定登录的页面
                .loginProcessingUrl("/login")//当登录页面提交时,会提交给哪个路径
                .failureUrl("/login.html?error")//登录失败从新登录,显示错误提示
                .defaultSuccessUrl("/index.html")//登录成功跳转到index.html
                .and().logout() //配置登出
                .logoutUrl("/logout")//设置登出路径
                //登出成功跳转登录页面,并提示已登出
                .logoutSuccessUrl("/login.html?logout");
    }
// 准备白名单,是不需要登录就可以访问的路径
    
    // 授权设置,是相对固定的配置
    // csrf().disable() > 关闭跨域攻击
    // authorizeRequests() > 对请求进行授权
    // antMatchers() > 配置访问白名单
    // permitAll() > 对白名单中的路径进行授权
    // anyRequest() > 其它的请求
    // authenticated() > 仅经过授权的允许访问,也可以理解为“未被授权将不允许访问”
    // and.formLogin() > 未被授权的将通过登录表单进行验证登录并授权
  • パラメータオブジェクトhttp呼び出すchainメソッドの構成は比較的固定されているか、理解してみるか、直接適用することができます。
  • 上記の呼び出しはantMatchers( )、SpringMVCインターセプターを使用する場合のホワイトリストの構成同等です。メソッドパラメーターで、直接解放する必要のあるすべてのパス(ログインせずにアクセスできる場所)を追加する必要があります。次に例を示します。

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 准备白名单,是不需要登录就可以访问的路径
       // String[] antMatchers = {
        //    "/index.html"
        //};
      
        String[] antMatchers = {
    	    "/index.html",
    	    "/bower_components/**",
            "/css/**",
            "/img/**",
            "/js/**"
        };
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers(antMatchers).permitAll()
                .anyRequest().authenticated()
                .and().formLogin();
    }

    ユーザーログイン-カスタムログインページを置き換えます

まず、Thymeleaf依存関係をプロジェクトに追加します。

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

カスタムログインページはHTMLテンプレートページとして設計されます。ログインURLが要求されると、HTMLテンプレートページに転送され、テンプレートフォルダがプロジェクトのsrc / main / resouecesの下に作成されます。これはによって使用されます。デフォルトのSpringBootプロジェクトテンプレートページフォルダを設定する必要はありません。転送時に、HTMLテンプレートファイルがデフォルトでこのフォルダに照会されます。フォルダが作成されたら、静的フォルダのlogin.htmlファイルをにドラッグします。テンプレートフォルダ。

次に、コントローラーをカスタマイズし、ログインページのリクエストパスを設計します。パスのリクエストを処理すると、/ templates /login.htmlファイルに直接転送されます。Thymeleafは統合中に/ templates /のプレフィックスをすでに構成しているためです。 、サフィックスは次のとおりです。構成は.htmlであるため、コントローラーに返されるビュー名はloginです。

コントロールレイヤーに新しいコントローラークラスを作成して、SystemControllerという名前のlogin.htmlページを表示しますコードは次のとおりです。

@RestController
public class SystemController {

    @GetMapping("/login.html")
    public ModelAndView loginForm(){
        return new ModelAndView("login");
    }

}
@Controller
public class SystemController {
 
    @GetMapping("/login.html")
    public String login() {
        return "login";
    }
 
    // 适用于使用@RestController时
    // public ModelAndView login() {
    //    return new ModelAndView("login");
    // }
 
}

 

 

 

 


 

おすすめ

転載: blog.csdn.net/c202003/article/details/115036902